[
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/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": "module-02-Creating-REST-APIS/01-Lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\n\n@Module({})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/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": "module-02-Creating-REST-APIS/01-Lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/01-Lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/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": "module-02-Creating-REST-APIS/02-Lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/src/songs/songs.controller.ts",
    "content": "import { Controller, Get, Put, Delete, Post } from '@nestjs/common';\n\n@Controller('songs')\nexport class SongsController {\n  @Post()\n  create() {\n    return 'create a new song endpoint';\n  }\n  @Get()\n  findAll() {\n    return 'find all songs endpoint';\n  }\n  @Get(':id')\n  findOne() {\n    return 'fetch song on the based on id';\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\n\n@Module({\n  controllers: [SongsController]\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/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": "module-02-Creating-REST-APIS/02-Lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/02-Lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/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": "module-02-Creating-REST-APIS/03-Lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/songs/songs.controller.ts",
    "content": "import { Controller, Get, Put, Delete, Post } from '@nestjs/common';\nimport { SongsService } from './songs.service';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create() {\n    return this.songsService.create('Animals by Martin Garrix');\n  }\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n  @Get(':id')\n  findOne() {\n    return 'fetch song on the based on id';\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService]\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/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": "module-02-Creating-REST-APIS/03-Lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-02-Creating-REST-APIS/03-Lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/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": "module-03-middlewares-exception-filters-pipes/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/app.module.ts",
    "content": "import {\n  MiddlewareConsumer,\n  Module,\n  NestModule,\n  RequestMethod,\n} from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/songs/songs.controller.ts",
    "content": "import { Controller, Get, Put, Delete, Post } from '@nestjs/common';\nimport { SongsService } from './songs.service';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create() {\n    return this.songsService.create('Animals by Martin Garrix');\n  }\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n  @Get(':id')\n  findOne() {\n    return 'fetch song on the based on id';\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService]\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/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": "module-03-middlewares-exception-filters-pipes/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/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": "module-03-middlewares-exception-filters-pipes/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/app.module.ts",
    "content": "import {\n  MiddlewareConsumer,\n  Module,\n  NestModule,\n  RequestMethod,\n} from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create() {\n    return this.songsService.create('Animals by Martin Garrix');\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne() {\n    return 'fetch song on the based on id';\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService]\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/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": "module-03-middlewares-exception-filters-pipes/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/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": "module-03-middlewares-exception-filters-pipes/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/app.module.ts",
    "content": "import {\n  MiddlewareConsumer,\n  Module,\n  NestModule,\n  RequestMethod,\n} from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create() {\n    return this.songsService.create('Animals by Martin Garrix');\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ) {\n    return `fetch song on the based on id ${typeof id}`;\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService]\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/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": "module-03-middlewares-exception-filters-pipes/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3001/songs\nContent-Type: application/json\n\n{\n    \"title\": \"lasting lover\",\n    \"artists\": [\"sigla\"],\n\"releasedDate\" : \"2022-09-29\",\n\"duration\" :\"02:34\"\n}\n\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/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": "module-03-middlewares-exception-filters-pipes/lesson-04/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/app.module.ts",
    "content": "import {\n  MiddlewareConsumer,\n  Module,\n  NestModule,\n  RequestMethod,\n} from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title: string;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString()\n  readonly artists: string[];\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO) {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ) {\n    return `fetch song on the based on id ${typeof id}`;\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService]\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/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": "module-03-middlewares-exception-filters-pipes/lesson-04/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-03-middlewares-exception-filters-pipes/lesson-04/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"lasting lover\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2022-09-29\",\n\"duration\" :\"02:34\"\n}\n\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/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": "module-04-dependency-injection/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\nconst devConfig = { port: 3000 };\nconst proConfig = { port: 4000 };\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [\n    AppService,\n    {\n      provide: DevConfigService,\n      useClass: DevConfigService,\n    },\n    {\n      provide: 'CONFIG',\n      useFactory: () => {\n        return process.env.NODE_ENV === 'development' ? devConfig : proConfig;\n      },\n    },\n  ],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  constructor(\n    private devConfigService: DevConfigService,\n    @Inject('CONFIG')\n    private config: { port: string },\n  ) {}\n  getHello(): string {\n    return `Hello I am learning Nest.js Fundamentals ${this.devConfigService.getDBHOST()} PORT = ${\n      this.config.port\n    }`;\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Connection } from 'src/common/constatnts/connection';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(\n    private songsService: SongsService,\n    @Inject('CONNECTION')\n    private connection: Connection,\n  ) {\n    console.log(\n      `THIS IS CONNECTION STRING ${this.connection.CONNECTION_STRING}`,\n    );\n  }\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO) {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ) {\n    return `fetch song on the based on id ${typeof id}`;\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { connection } from 'src/common/constatnts/connection';\n\nconst mockSongsService = {\n  findAll() {\n    return [{ id: 1, title: 'Lasting lover', artists: ['Siagla'] }];\n  },\n};\n\n@Module({\n  controllers: [SongsController],\n  providers: [\n    SongsService,\n    // {\n    //   provide: SongsService,\n    //   useClass: SongsService,\n    // },\n    // {\n    //   provide: SongsService,\n    //   useValue: mockSongsService,\n    // },\n    {\n      provide: 'CONNECTION',\n      useValue: connection,\n    },\n  ],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    // throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/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": "module-04-dependency-injection/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"lasting lover\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2022-09-29\",\n\"duration\" :\"02:34\"\n}\n\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/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": "module-04-dependency-injection/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\nconst devConfig = { port: 3000 };\nconst proConfig = { port: 4000 };\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [\n    AppService,\n    {\n      provide: DevConfigService,\n      useClass: DevConfigService,\n    },\n    {\n      provide: 'CONFIG',\n      useFactory: () => {\n        return process.env.NODE_ENV === 'development' ? devConfig : proConfig;\n      },\n    },\n  ],\n})\nexport class AppModule implements NestModule {\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  constructor(\n    private devConfigService: DevConfigService,\n    @Inject('CONFIG')\n    private config: { port: string },\n  ) {}\n  getHello(): string {\n    return `Hello I am learning Nest.js Fundamentals ${this.devConfigService.getDBHOST()} PORT = ${\n      this.config.port\n    }`;\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Connection } from 'src/common/constatnts/connection';\n\n@Controller({ path: 'songs', scope: Scope.REQUEST })\nexport class SongsController {\n  constructor(\n    private songsService: SongsService,\n    @Inject('CONNECTION')\n    private connection: Connection,\n  ) {\n    console.log(\n      `THIS IS CONNECTION STRING ${this.connection.CONNECTION_STRING}`,\n    );\n  }\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO) {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ) {\n    return `fetch song on the based on id ${typeof id}`;\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { connection } from 'src/common/constatnts/connection';\n\nconst mockSongsService = {\n  findAll() {\n    return [{ id: 1, title: 'Lasting lover', artists: ['Siagla'] }];\n  },\n};\n\n@Module({\n  controllers: [SongsController],\n  providers: [\n    SongsService,\n    // {\n    //   provide: SongsService,\n    //   useClass: SongsService,\n    // },\n    // {\n    //   provide: SongsService,\n    //   useValue: mockSongsService,\n    // },\n    {\n      provide: 'CONNECTION',\n      useValue: connection,\n    },\n  ],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/src/songs/songs.service.ts",
    "content": "import { Injectable, Scope } from '@nestjs/common';\n\n@Injectable({\n  scope: Scope.TRANSIENT,\n})\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    // throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/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": "module-04-dependency-injection/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-04-dependency-injection/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"lasting lover\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2022-09-29\",\n\"duration\" :\"02:34\"\n}\n\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/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": "module-05-connect-nestjs-to-postgress/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { DataSource } from 'typeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [],\n      synchronize: true,\n    }),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(private dataSource: DataSource) {\n    console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO) {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ) {\n    return `fetch song on the based on id ${typeof id}`;\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    // throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/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": "module-05-connect-nestjs-to-postgress/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"lasting lover\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2022-09-29\",\n\"duration\" :\"02:34\"\n}\n\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/1\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/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": "module-05-connect-nestjs-to-postgress/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\n// import { DataSource } from 'typeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song],\n      synchronize: true,\n    }),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  @Column('varchar', { array: true })\n  artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO) {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll() {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ) {\n    return `fetch song on the based on id ${typeof id}`;\n  }\n\n  @Put(':id')\n  update() {\n    return 'update song on the based on id';\n  }\n\n  @Delete(':id')\n  delete() {\n    return 'delete song on the based on id';\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class SongsService {\n  // local db\n  // local array\n\n  private readonly songs = [];\n\n  create(song) {\n    // Save the song in the database\n    this.songs.push(song);\n    return this.songs;\n  }\n\n  findAll() {\n    // fetch the songs from the db\n    // Errors comes while fetching the data from DB\n    // throw new Error('Error in Db whil fetching record');\n    return this.songs;\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/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": "module-05-connect-nestjs-to-postgress/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"lasting lover 2\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2022-09-29\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/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": "module-05-connect-nestjs-to-postgress/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\n// import { DataSource } from 'typeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song],\n      synchronize: true,\n    }),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  @Column('varchar', { array: true })\n  artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(): Promise<Song[]> {\n    try {\n      return this.songsService.findAll();\n    } catch (e) {\n      throw new HttpException(\n        'server error',\n        HttpStatus.INTERNAL_SERVER_ERROR,\n        {\n          cause: e,\n        },\n      );\n    }\n  }\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n  ) {}\n\n  create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/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": "module-05-connect-nestjs-to-postgress/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"New Song 5\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/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": "module-05-connect-nestjs-to-postgress/lesson-04/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\n// import { DataSource } from 'typeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song],\n      synchronize: true,\n    }),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  @Column('varchar', { array: true })\n  artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n  ) {}\n\n  create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/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": "module-05-connect-nestjs-to-postgress/lesson-04/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-05-connect-nestjs-to-postgress/lesson-04/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-06-relations/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-06-relations/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-06-relations/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-06-relations/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"New Song 5\",\n\"artists\": [\n    \"Siagla\",\n    \"Martin\",\n    \"John\"\n],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1"
  },
  {
    "path": "module-06-relations/lesson-01/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": "module-06-relations/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\n// import { DataSource } from 'typeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User],\n      synchronize: true,\n    }),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/artists/artist.entity.ts",
    "content": "import { User } from 'src/users/user.entity';\nimport { Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsString({ each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  @Column('varchar', { array: true })\n  artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n  ) {}\n\n  create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/src/users/user.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column()\n  email: string;\n\n  @Column()\n  password: string;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-06-relations/lesson-01/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": "module-06-relations/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-06-relations/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/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": "module-06-relations/lesson-02-and-lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/src/users/user.entity.ts",
    "content": "import { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column()\n  email: string;\n\n  @Column()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/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": "module-06-relations/lesson-02-and-lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-06-relations/lesson-02-and-lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"bcryptjs\": \"^2.4.3\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\",\n    \"@types/bcryptjs\": \"^2.4.2\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/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": "module-07-authetication-and-authorization/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-01',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(private userService: UsersService) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\n\n@Module({\n  imports: [UsersModule],\n  providers: [AuthService],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AuthService {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/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": "module-07-authetication-and-authorization/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"passport\": \"^0.6.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\",\n    \"@types/bcryptjs\": \"^2.4.2\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/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": "module-07-authetication-and-authorization/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-01',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\n\n@Module({\n  imports: [UsersModule],\n  providers: [AuthService],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\n\n@Injectable()\nexport class AuthService {\n  constructor(private userService: UsersService) {}\n\n  async login(loginDTO: LoginDTO): Promise<User> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    ); // 2.\n\n    if (passwordMatched) {\n      //3\n      delete user.password; // 4.\n      return user;\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/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": "module-07-authetication-and-authorization/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"passport-jwt\": \"^4.0.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/passport-jwt\": \"^3.0.8\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/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": "module-07-authetication-and-authorization/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-01',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/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": "module-07-authetication-and-authorization/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"passport-jwt\": \"^4.0.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/passport-jwt\": \"^3.0.8\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/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": "module-07-authetication-and-authorization/lesson-04/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-01',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/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": "module-07-authetication-and-authorization/lesson-04/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-04/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"speakeasy\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/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": "module-07-authetication-and-authorization/lesson-05/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-01',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/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": "module-07-authetication-and-authorization/lesson-05/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-05/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/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": "module-07-authetication-and-authorization/lesson-06/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-02',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/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": "module-07-authetication-and-authorization/lesson-06/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-07-authetication-and-authorization/lesson-06/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/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": "module-08-migrations-seeds-debugging/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'spotify-clone-02',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/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": "module-08-migrations-seeds-debugging/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/db/data-source.ts",
    "content": "import { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: 'localhost',\n  port: 5432,\n  username: 'postgres',\n  password: 'root',\n  database: 'spotify-clone',\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/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": "module-08-migrations-seeds-debugging/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { dataSourceOptions } from 'db/data-source';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot(dataSourceOptions),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/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": "module-08-migrations-seeds-debugging/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/db/data-source.ts",
    "content": "import { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: 'localhost',\n  port: 5432,\n  username: 'postgres',\n  password: 'root',\n  database: 'spotify-clone',\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/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": "module-08-migrations-seeds-debugging/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { dataSourceOptions } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot(dataSourceOptions),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/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": "module-08-migrations-seeds-debugging/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-08-migrations-seeds-debugging/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-09-application-configurations/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-09-application-configurations/lesson-01/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: ['dist/**/*.entity.js'],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkwNzIsImV4cCI6MTY4NDk5NTQ3Mn0.wYEhyDMor-bs2_Ghmcno0mEJqkqkP9XwOrKUDf0YAZc\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-09-application-configurations/lesson-01/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": "module-09-application-configurations/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n}\nbootstrap();\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/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": "module-09-application-configurations/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-09-application-configurations/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-09-application-configurations/lesson-02/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: ['dist/**/*.entity.js'],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-09-application-configurations/lesson-02/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": "module-09-application-configurations/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n}\nbootstrap();\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/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": "module-09-application-configurations/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-09-application-configurations/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-09-application-configurations/lesson-03/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: ['dist/**/*.entity.js'],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-09-application-configurations/lesson-03/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": "module-09-application-configurations/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/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": "module-09-application-configurations/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-09-application-configurations/lesson-03/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: ['dist/**/*.entity.js'],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\",\n    \"@nestjs/swagger\": \"^6.3.0\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/swagger\": \"^6.3.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/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": "module-10-api-documentation-with-swagger/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n\n  const config = new DocumentBuilder() //1\n    .setTitle('Spotify Clone')\n    .setDescription('The Spotify Clone Api documentation')\n    .setVersion('1.0')\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config); //2\n  SwaggerModule.setup('api', app, document); //3\n\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/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": "module-10-api-documentation-with-swagger/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-01/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: [User, Playlist, Artist, Song],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\",\n    \"@nestjs/swagger\": \"^6.3.0\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/swagger\": \"^6.3.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/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": "module-10-api-documentation-with-swagger/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\n@Controller('auth')\n@ApiTags('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  @ApiOperation({ summary: 'Register new user' })\n  @ApiResponse({\n    status: 201,\n    description: 'It will return the user in the response',\n  })\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n\n  const config = new DocumentBuilder() //1\n    .setTitle('Spotify Clone')\n    .setDescription('The Spotify Clone Api documentation')\n    .setVersion('1.0')\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config); //2\n  SwaggerModule.setup('api', app, document); //3\n\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/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": "module-10-api-documentation-with-swagger/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-02/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: [User, Playlist, Artist, Song],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"plugins\": [\n      {\n        \"name\": \"@nestjs/swagger\",\n        \"options\": {\n          \"introspectComments\": true\n        }\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\",\n    \"@nestjs/swagger\": \"^6.3.0\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/swagger\": \"^6.3.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/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": "module-10-api-documentation-with-swagger/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\n@Controller('auth')\n@ApiTags('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  @ApiOperation({ summary: 'Register new user' })\n  @ApiResponse({\n    status: 201,\n    description: 'It will return the user in the response',\n  })\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n\n  const config = new DocumentBuilder() //1\n    .setTitle('Spotify Clone')\n    .setDescription('The Spotify Clone Api documentation')\n    .setVersion('1.0')\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config); //2\n  SwaggerModule.setup('api', app, document); //3\n\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/users/user.entity.ts",
    "content": "import { ApiProperty } from '@nestjs/swagger';\nimport { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @ApiProperty({\n    example: 'Jane',\n    description: 'provide the firstName of the user',\n  })\n  @Column()\n  firstName: string;\n\n  @ApiProperty({\n    example: 'Doe',\n    description: 'provide the lastName of the user',\n  })\n  @Column()\n  lastName: string;\n\n  @ApiProperty({\n    example: 'jane_doe@gmail.com',\n    description: 'provide the email of the user',\n  })\n  @Column({ unique: true })\n  email: string;\n\n  @ApiProperty({\n    description: 'provide the password of the user',\n  })\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/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": "module-10-api-documentation-with-swagger/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-03/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: [User, Playlist, Artist, Song],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"plugins\": [\n      {\n        \"name\": \"@nestjs/swagger\",\n        \"options\": {\n          \"introspectComments\": true\n        }\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\",\n    \"@nestjs/swagger\": \"^6.3.0\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/swagger\": \"^6.3.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/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": "module-10-api-documentation-with-swagger/lesson-04/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\nimport { ApiBearerAuth } from '@nestjs/swagger';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  @ApiBearerAuth('JWT-auth') //1\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\n@Controller('auth')\n@ApiTags('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  @ApiOperation({ summary: 'Register new user' })\n  @ApiResponse({\n    status: 201,\n    description: 'It will return the user in the response',\n  })\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  @ApiOperation({ summary: 'Login user' })\n  @ApiResponse({\n    status: 200,\n    description: 'It will give you the access_token in the response',\n  })\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: process.env.SECRET,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n\n  const config = new DocumentBuilder() //1\n    .setTitle('Spotify Clone')\n    .setDescription('The Spotify Clone Api documentation')\n    .setVersion('1.0')\n    .addBearerAuth(\n      // Enable Bearer Auth here\n      {\n        type: 'http',\n        scheme: 'bearer',\n        bearerFormat: 'JWT',\n        name: 'JWT',\n        description: 'Enter JWT token',\n        in: 'header',\n      },\n      'JWT-auth', // We will use this Bearer Auth with JWT-auth name on the controller function\n    )\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config); //2\n  SwaggerModule.setup('api', app, document); //3\n\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\nimport { ApiTags } from '@nestjs/swagger';\n\n@Controller('playlists')\n@ApiTags('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\nimport { ApiTags } from '@nestjs/swagger';\n\n@Controller('songs')\n@ApiTags('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/users/user.entity.ts",
    "content": "import { ApiProperty } from '@nestjs/swagger';\nimport { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @ApiProperty({\n    example: 'Jane',\n    description: 'provide the firstName of the user',\n  })\n  @Column()\n  firstName: string;\n\n  @ApiProperty({\n    example: 'Doe',\n    description: 'provide the lastName of the user',\n  })\n  @Column()\n  lastName: string;\n\n  @ApiProperty({\n    example: 'jane_doe@gmail.com',\n    description: 'provide the email of the user',\n  })\n  @Column({ unique: true })\n  email: string;\n\n  @ApiProperty({\n    description: 'provide the password of the user',\n  })\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/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": "module-10-api-documentation-with-swagger/lesson-04/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-10-api-documentation-with-swagger/lesson-04/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-11-mongodb/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-11-mongodb/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mongodb: \n    image: mongo:latest\n    environment:\n      - MONGODB_DATABASE=\"spotify-clone\"\n    ports:\n      - 27017:27017"
  },
  {
    "path": "module-11-mongodb/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-mongo-production\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/mongoose\": \"^9.2.2\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"mongoose\": \"^7.2.2\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/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": "module-11-mongodb/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { MongooseModule } from '@nestjs/mongoose';\n\n@Module({\n  imports: [MongooseModule.forRoot('mongodb://localhost:27017/spotify-clone')],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/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": "module-11-mongodb/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mongodb: \n    image: mongo:latest\n    environment:\n      - MONGODB_DATABASE=\"spotify-clone\"\n    ports:\n      - 27017:27017"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/package.json",
    "content": "{\n  \"name\": \"n-mongo-production\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/mongoose\": \"^9.2.2\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"mongoose\": \"^7.2.2\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/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": "module-11-mongodb/lesson-02-and-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { MongooseModule } from '@nestjs/mongoose';\n\n@Module({\n  imports: [MongooseModule.forRoot('mongodb://localhost:27017/spotify-clone')],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/src/songs/schemas/song.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument } from 'mongoose';\n\nexport type SongDocument = HydratedDocument<Song>; //1.\n\n@Schema() //2.\nexport class Song {\n  @Prop({\n    // 3.\n    required: true,\n  })\n  title: string;\n\n  @Prop({\n    required: true,\n  })\n  releasedDate: Date;\n\n  @Prop({\n    required: true,\n  })\n  duration: string;\n\n  lyrics: string;\n}\n\nexport const SongSchema = SchemaFactory.createForClass(Song);\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/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": "module-11-mongodb/lesson-02-and-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-02-and-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-11-mongodb/lesson-04/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-11-mongodb/lesson-04/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/api.http",
    "content": "### Create Song \nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n     \"title\": \"Love me\",\n    \"releasedDate\" : \"2023-05-11\",\n    \"duration\" :\"02:33\",\n    \"lyrics\": \"1adas adsdasd asdasdasd qeqew\"\n}"
  },
  {
    "path": "module-11-mongodb/lesson-04/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mongodb: \n    image: mongo:latest\n    environment:\n      - MONGODB_DATABASE=\"spotify-clone\"\n    ports:\n      - 27017:27017"
  },
  {
    "path": "module-11-mongodb/lesson-04/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/package.json",
    "content": "{\n  \"name\": \"n-mongo-production\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/mongoose\": \"^9.2.2\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"mongoose\": \"^7.2.2\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/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": "module-11-mongodb/lesson-04/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [\n    MongooseModule.forRoot('mongodb://localhost:27017/spotify-clone'),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/dto/create-song-dto.ts",
    "content": "export class CreateSongDTO {\n  title: string;\n  releasedDate: Date;\n  duration: Date;\n  lyrics: string;\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/schemas/song.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument } from 'mongoose';\n\nexport type SongDocument = HydratedDocument<Song>; //1.\n\n@Schema() //2.\nexport class Song {\n  @Prop({\n    // 3.\n    required: true,\n  })\n  title: string;\n\n  @Prop({\n    required: true,\n  })\n  releasedDate: Date;\n\n  @Prop({\n    required: true,\n  })\n  duration: string;\n\n  lyrics: string;\n}\n\nexport const SongSchema = SchemaFactory.createForClass(Song);\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/songs.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { SongsService } from './songs.service';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songService: SongsService) {}\n  @Post()\n  create(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ) {\n    return this.songService.create(createSongDTO);\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { Song, SongSchema } from './schemas/song';\nimport { MongooseModule } from '@nestjs/mongoose';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Song.name, schema: SongSchema }]),\n  ],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { Model } from 'mongoose';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song, SongDocument } from './schemas/song';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectModel(Song.name) //1\n    private readonly songModel: Model<SongDocument>, //2\n  ) {}\n\n  async create(createSongDTO: CreateSongDTO): Promise<Song> {\n    const song = await this.songModel.create(createSongDTO); //3.\n    return song;\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/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": "module-11-mongodb/lesson-04/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-04/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-11-mongodb/lesson-05/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-11-mongodb/lesson-05/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/api.http",
    "content": "### Create Song \nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n     \"title\": \"New song\",\n    \"releasedDate\" : \"2023-05-11\",\n    \"duration\" :\"02:33\",\n    \"lyrics\": \"1adas adsdasd asdasdasd qeqew\"\n}\n\n### Find all songs\nGET http://localhost:3000/songs\n\n\n### Find one song\n\nGET http://localhost:3000/songs/6481786f31a6103e10489ced\n\n### Delete Song\n\nDELETE http://localhost:3000/songs/6481793569b739d7236e73b3"
  },
  {
    "path": "module-11-mongodb/lesson-05/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mongodb: \n    image: mongo:latest\n    environment:\n      - MONGODB_DATABASE=\"spotify-clone\"\n    ports:\n      - 27017:27017"
  },
  {
    "path": "module-11-mongodb/lesson-05/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/package.json",
    "content": "{\n  \"name\": \"n-mongo-production\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/mongoose\": \"^9.2.2\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"mongoose\": \"^7.2.2\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/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": "module-11-mongodb/lesson-05/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [\n    MongooseModule.forRoot('mongodb://localhost:27017/spotify-clone'),\n    SongsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/dto/create-song-dto.ts",
    "content": "export class CreateSongDTO {\n  title: string;\n  releasedDate: Date;\n  duration: Date;\n  lyrics: string;\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/schemas/song.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument } from 'mongoose';\n\nexport type SongDocument = HydratedDocument<Song>; //1.\n\n@Schema() //2.\nexport class Song {\n  @Prop({\n    // 3.\n    required: true,\n  })\n  title: string;\n\n  @Prop({\n    required: true,\n  })\n  releasedDate: Date;\n\n  @Prop({\n    required: true,\n  })\n  duration: string;\n\n  lyrics: string;\n}\n\nexport const SongSchema = SchemaFactory.createForClass(Song);\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/songs.controller.ts",
    "content": "import { Body, Controller, Post, Get, Param, Delete } from '@nestjs/common';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { SongsService } from './songs.service';\nimport { Song } from './schemas/song';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songService: SongsService) {}\n  @Post()\n  create(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ) {\n    return this.songService.create(createSongDTO);\n  }\n\n  @Get()\n  find(): Promise<Song[]> {\n    return this.songService.find();\n  }\n\n  @Get(':id')\n  findOne(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.findById(id);\n  }\n\n  @Delete(':id')\n  delete(\n    @Param('id')\n    id: string,\n  ) {\n    return this.songService.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { Song, SongSchema } from './schemas/song';\nimport { MongooseModule } from '@nestjs/mongoose';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Song.name, schema: SongSchema }]),\n  ],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { Model } from 'mongoose';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song, SongDocument } from './schemas/song';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectModel(Song.name) //1\n    private readonly songModel: Model<SongDocument>, //2\n  ) {}\n\n  async create(createSongDTO: CreateSongDTO): Promise<Song> {\n    const song = await this.songModel.create(createSongDTO); //3.\n    return song;\n  }\n\n  async find(): Promise<Song[]> {\n    return this.songModel.find();\n  }\n\n  async findById(id: string): Promise<Song> {\n    return this.songModel.findById(id);\n  }\n  async delete(id: string) {\n    return this.songModel.deleteOne({ _id: id });\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/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": "module-11-mongodb/lesson-05/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-05/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-11-mongodb/lesson-06/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-11-mongodb/lesson-06/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/api.http",
    "content": "### Create Song \nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n     \"title\": \"New song\",\n    \"releasedDate\" : \"2023-05-11\",\n    \"duration\" :\"02:33\",\n    \"lyrics\": \"1adas adsdasd asdasdasd qeqew\"\n}\n\n### Find all songs\nGET http://localhost:3000/songs\n\n\n### Find one song\n\nGET http://localhost:3000/songs/6481786f31a6103e10489ced\n\n### Delete Song\n\nDELETE http://localhost:3000/songs/6481793569b739d7236e73b3\n\n### Create Album\nPOST http://localhost:3000/albums\nContent-Type: application/json\n\n{\n    \"title\": \"Dance\",\n    \"songs\": [\"6481786f31a6103e10489ced\",\"6481787831a6103e10489cef\"]\n}\n\n### Find all albums with songs\n\nGET http://localhost:3000/albums"
  },
  {
    "path": "module-11-mongodb/lesson-06/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mongodb: \n    image: mongo:latest\n    environment:\n      - MONGODB_DATABASE=\"spotify-clone\"\n    ports:\n      - 27017:27017"
  },
  {
    "path": "module-11-mongodb/lesson-06/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/package.json",
    "content": "{\n  \"name\": \"n-mongo-production\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/mongoose\": \"^9.2.2\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"mongoose\": \"^7.2.2\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/albums/albums.controller.ts",
    "content": "import { Body, Controller, Get, Post } from '@nestjs/common';\nimport { Album } from './schemas/album.schema';\nimport { AlbumsService } from './albums.service';\nimport { CreateAlbumDTO } from './dto/create-album-dto';\n\n@Controller('albums')\nexport class AlbumsController {\n  constructor(private albumService: AlbumsService) {}\n  @Post()\n  create(\n    @Body()\n    createAlbumDTO: CreateAlbumDTO,\n  ): Promise<Album> {\n    return this.albumService.createAlbum(createAlbumDTO);\n  }\n\n  @Get()\n  find(): Promise<Album[]> {\n    return this.albumService.findAlbums();\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/albums/albums.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AlbumsController } from './albums.controller';\nimport { AlbumsService } from './albums.service';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { Album, AlbumSchema } from './schemas/album.schema';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Album.name, schema: AlbumSchema }]),\n  ],\n  controllers: [AlbumsController],\n  providers: [AlbumsService],\n})\nexport class AlbumsModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/albums/albums.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Album, AlbumDocument } from './schemas/album.schema';\nimport { Model } from 'mongoose';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { CreateAlbumDTO } from './dto/create-album-dto';\nimport { Song } from 'src/songs/schemas/song';\n\n@Injectable()\nexport class AlbumsService {\n  constructor(\n    @InjectModel(Album.name)\n    private readonly albumModel: Model<AlbumDocument>,\n  ) {}\n  async createAlbum(createAlbumDTO: CreateAlbumDTO): Promise<Album> {\n    return this.albumModel.create(createAlbumDTO);\n  }\n\n  async findAlbums() {\n    return this.albumModel.find().populate('songs', null, Song.name); //1\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/albums/dto/create-album-dto.ts",
    "content": "export class CreateAlbumDTO {\n  title: string;\n  songs: string[];\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/albums/schemas/album.schema.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument, Schema as MongooseSchema, Types } from 'mongoose';\nimport { Song } from 'src/songs/schemas/song';\n\nexport type AlbumDocument = HydratedDocument<Album>;\n\n@Schema()\nexport class Album {\n  @Prop({\n    required: true,\n  })\n  title: string;\n\n  @Prop({ type: [Types.ObjectId], ref: 'songs' }) //1\n  songs: Song[];\n}\n\nexport const AlbumSchema = SchemaFactory.createForClass(Album);\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/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": "module-11-mongodb/lesson-06/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { SongsModule } from './songs/songs.module';\nimport { AlbumsModule } from './albums/albums.module';\n\n@Module({\n  imports: [\n    MongooseModule.forRoot('mongodb://localhost:27017/spotify-clone'),\n    SongsModule,\n    AlbumsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/dto/create-song-dto.ts",
    "content": "export class CreateSongDTO {\n  title: string;\n  releasedDate: Date;\n  duration: Date;\n  lyrics: string;\n  album: string;\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/schemas/song.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument, Types } from 'mongoose';\nimport { Album } from 'src/albums/schemas/album.schema';\n\nexport type SongDocument = HydratedDocument<Song>; //1.\n\n@Schema() //2.\nexport class Song {\n  @Prop({\n    // 3.\n    required: true,\n  })\n  title: string;\n\n  @Prop({\n    required: true,\n  })\n  releasedDate: Date;\n\n  @Prop({\n    required: true,\n  })\n  duration: string;\n\n  @Prop()\n  lyrics: string;\n\n  // song.schema.ts\n  @Prop({\n    type: Types.ObjectId,\n    ref: Album.name,\n  })\n  album: Album;\n}\n\nexport const SongSchema = SchemaFactory.createForClass(Song);\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/songs.controller.ts",
    "content": "import { Body, Controller, Post, Get, Param, Delete } from '@nestjs/common';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { SongsService } from './songs.service';\nimport { Song } from './schemas/song';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songService: SongsService) {}\n  @Post()\n  create(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ) {\n    return this.songService.create(createSongDTO);\n  }\n\n  @Get()\n  find(): Promise<Song[]> {\n    return this.songService.find();\n  }\n\n  @Get(':id')\n  findOne(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.findById(id);\n  }\n\n  @Delete(':id')\n  delete(\n    @Param('id')\n    id: string,\n  ) {\n    return this.songService.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { Song, SongSchema } from './schemas/song';\nimport { MongooseModule } from '@nestjs/mongoose';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Song.name, schema: SongSchema }]),\n  ],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { Model } from 'mongoose';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song, SongDocument } from './schemas/song';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectModel(Song.name) //1\n    private readonly songModel: Model<SongDocument>, //2\n  ) {}\n\n  async create(createSongDTO: CreateSongDTO): Promise<Song> {\n    const song = await this.songModel.create(createSongDTO); //3.\n    return song;\n  }\n\n  async find(): Promise<Song[]> {\n    return this.songModel.find();\n  }\n\n  async findById(id: string): Promise<Song> {\n    return this.songModel.findById(id);\n  }\n  async delete(id: string) {\n    return this.songModel.deleteOne({ _id: id });\n  }\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/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": "module-11-mongodb/lesson-06/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-11-mongodb/lesson-06/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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.env"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\n//LOAD Environment Variables\nrequire('dotenv').config();\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: [User, Playlist, Artist, Song],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n// console.log(process.env.NODE_ENV);\n// console.log(process.env.DB_HOST); // these variables are undefined\n// console.log(process.env.PASSWORD);\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/db/migrations/1686309549613-init.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class Init1686309549613 implements MigrationInterface {\n    name = 'Init1686309549613'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"plugins\": [\n      {\n        \"name\": \"@nestjs/swagger\",\n        \"options\": {\n          \"introspectComments\": true\n        }\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"NODE_ENV=development nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"NODE_ENV=production node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\",\n    \"@nestjs/swagger\": \"^6.3.0\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/swagger\": \"^6.3.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"dotenv\": \"^16.1.4\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/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": "module-12-deploy-nestjs/deployment-finish/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\nimport { ApiBearerAuth } from '@nestjs/swagger';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  @ApiBearerAuth('JWT-auth') //1\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: [`${process.cwd()}/.env.${process.env.NODE_ENV}`],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\n@Controller('auth')\n@ApiTags('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  @ApiOperation({ summary: 'Register new user' })\n  @ApiResponse({\n    status: 201,\n    description: 'It will return the user in the response',\n  })\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  @ApiOperation({ summary: 'Login user' })\n  @ApiResponse({\n    status: 200,\n    description: 'It will give you the access_token in the response',\n  })\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: process.env.SECRET,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/config/configuration.ts",
    "content": "export default () => ({\n  NODE_ENV: process.env.NODE_ENV,\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n\n  const config = new DocumentBuilder() //1\n    .setTitle('Spotify Clone')\n    .setDescription('The Spotify Clone Api documentation')\n    .setVersion('1.0')\n    .addBearerAuth(\n      // Enable Bearer Auth here\n      {\n        type: 'http',\n        scheme: 'bearer',\n        bearerFormat: 'JWT',\n        name: 'JWT',\n        description: 'Enter JWT token',\n        in: 'header',\n      },\n      'JWT-auth', // We will use this Bearer Auth with JWT-auth name on the controller function\n    )\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config); //2\n  SwaggerModule.setup('api', app, document); //3\n\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n  console.log(configService.get<string>('NODE_ENV'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\nimport { ApiTags } from '@nestjs/swagger';\n\n@Controller('playlists')\n@ApiTags('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\nimport { ApiTags } from '@nestjs/swagger';\n\n@Controller('songs')\n@ApiTags('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/users/user.entity.ts",
    "content": "import { ApiProperty } from '@nestjs/swagger';\nimport { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @ApiProperty({\n    example: 'Jane',\n    description: 'provide the firstName of the user',\n  })\n  @Column()\n  firstName: string;\n\n  @ApiProperty({\n    example: 'Doe',\n    description: 'provide the lastName of the user',\n  })\n  @Column()\n  lastName: string;\n\n  @ApiProperty({\n    example: 'jane_doe@gmail.com',\n    description: 'provide the email of the user',\n  })\n  @Column({ unique: true })\n  email: string;\n\n  @ApiProperty({\n    description: 'provide the password of the user',\n  })\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/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": "module-12-deploy-nestjs/deployment-finish/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-finish/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/db/data-source.ts",
    "content": "import { ConfigModule, ConfigService } from '@nestjs/config';\nimport {\n  TypeOrmModuleAsyncOptions,\n  TypeOrmModuleOptions,\n} from '@nestjs/typeorm';\nimport { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport { DataSource, DataSourceOptions } from 'typeorm';\n\nexport const typeOrmAsyncConfig: TypeOrmModuleAsyncOptions = {\n  imports: [ConfigModule],\n  inject: [ConfigService],\n  useFactory: async (\n    configService: ConfigService,\n  ): Promise<TypeOrmModuleOptions> => {\n    return {\n      type: 'postgres',\n      host: configService.get<string>('dbHost'),\n      port: configService.get<number>('dbPort'),\n      username: configService.get<string>('username'),\n      database: configService.get<string>('dbName'),\n      password: configService.get<string>('password'),\n      entities: [User, Playlist, Artist, Song],\n      synchronize: false,\n      migrations: ['dist/db/migrations/*.js'],\n    };\n  },\n};\n\nexport const dataSourceOptions: DataSourceOptions = {\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n  entities: ['dist/**/*.entity.js'], //1\n  synchronize: false, // 2\n  migrations: ['dist/db/migrations/*.js'], // 3\n};\n\nconst dataSource = new DataSource(dataSourceOptions); //4\nexport default dataSource;\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/db/migrations/1685010320827-my-migrations.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class MyMigrations1685010320827 implements MigrationInterface {\n    name = 'MyMigrations1685010320827'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`CREATE TABLE \"users\" (\"id\" SERIAL NOT NULL, \"firstName\" character varying NOT NULL, \"lastName\" character varying NOT NULL, \"email\" character varying NOT NULL, \"password\" character varying NOT NULL, \"twoFASecret\" text, \"enable2FA\" boolean NOT NULL DEFAULT false, \"apiKey\" character varying NOT NULL, \"phone\" character varying NOT NULL, CONSTRAINT \"UQ_97672ac88f789774dd47f7c8be3\" UNIQUE (\"email\"), CONSTRAINT \"PK_a3ffb1c0c8416b9fc6f907b7433\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"playlists\" (\"id\" SERIAL NOT NULL, \"name\" character varying NOT NULL, \"userId\" integer, CONSTRAINT \"PK_a4597f4189a75d20507f3f7ef0d\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs\" (\"id\" SERIAL NOT NULL, \"title\" character varying NOT NULL, \"releasedDate\" date NOT NULL, \"duration\" TIME NOT NULL, \"lyrics\" text NOT NULL, \"playListId\" integer, CONSTRAINT \"PK_e504ce8ad2e291d3a1d8f1ea2f4\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"artists\" (\"id\" SERIAL NOT NULL, \"userId\" integer, CONSTRAINT \"REL_f7bd9114dc2849a90d39512911\" UNIQUE (\"userId\"), CONSTRAINT \"PK_09b823d4607d2675dc4ffa82261\" PRIMARY KEY (\"id\"))`);\n        await queryRunner.query(`CREATE TABLE \"songs_artists\" (\"songsId\" integer NOT NULL, \"artistsId\" integer NOT NULL, CONSTRAINT \"PK_78eb64551964b78d544c2ac019b\" PRIMARY KEY (\"songsId\", \"artistsId\"))`);\n        await queryRunner.query(`CREATE INDEX \"IDX_971d95bf6df45f2b07c317b6b3\" ON \"songs_artists\" (\"songsId\") `);\n        await queryRunner.query(`CREATE INDEX \"IDX_3f43a7e4032521e4edd2e7ecd2\" ON \"songs_artists\" (\"artistsId\") `);\n        await queryRunner.query(`ALTER TABLE \"playlists\" ADD CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs\" ADD CONSTRAINT \"FK_54cf41bc33d524b206b93581950\" FOREIGN KEY (\"playListId\") REFERENCES \"playlists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"artists\" ADD CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\" FOREIGN KEY (\"userId\") REFERENCES \"users\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\" FOREIGN KEY (\"songsId\") REFERENCES \"songs\"(\"id\") ON DELETE CASCADE ON UPDATE CASCADE`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" ADD CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\" FOREIGN KEY (\"artistsId\") REFERENCES \"artists\"(\"id\") ON DELETE NO ACTION ON UPDATE NO ACTION`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_3f43a7e4032521e4edd2e7ecd29\"`);\n        await queryRunner.query(`ALTER TABLE \"songs_artists\" DROP CONSTRAINT \"FK_971d95bf6df45f2b07c317b6b34\"`);\n        await queryRunner.query(`ALTER TABLE \"artists\" DROP CONSTRAINT \"FK_f7bd9114dc2849a90d39512911b\"`);\n        await queryRunner.query(`ALTER TABLE \"songs\" DROP CONSTRAINT \"FK_54cf41bc33d524b206b93581950\"`);\n        await queryRunner.query(`ALTER TABLE \"playlists\" DROP CONSTRAINT \"FK_708a919e9aa49019000d9e9b68e\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_3f43a7e4032521e4edd2e7ecd2\"`);\n        await queryRunner.query(`DROP INDEX \"public\".\"IDX_971d95bf6df45f2b07c317b6b3\"`);\n        await queryRunner.query(`DROP TABLE \"songs_artists\"`);\n        await queryRunner.query(`DROP TABLE \"artists\"`);\n        await queryRunner.query(`DROP TABLE \"songs\"`);\n        await queryRunner.query(`DROP TABLE \"playlists\"`);\n        await queryRunner.query(`DROP TABLE \"users\"`);\n    }\n\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/db/migrations/1685010456982-removed-phone.ts",
    "content": "import { MigrationInterface, QueryRunner } from \"typeorm\";\n\nexport class RemovedPhone1685010456982 implements MigrationInterface {\n    name = 'RemovedPhone1685010456982'\n\n    public async up(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" DROP COLUMN \"phone\"`);\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<void> {\n        await queryRunner.query(`ALTER TABLE \"users\" ADD \"phone\" character varying NOT NULL`);\n    }\n\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/db/seeds/seed-data.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { User } from 'src/users/user.entity';\nimport { EntityManager } from 'typeorm';\nimport { faker } from '@faker-js/faker';\nimport { v4 as uuid4 } from 'uuid';\nimport * as bcrypt from 'bcryptjs';\nimport { Playlist } from '../../src/playlists/playlist.entity';\n\nexport const seedData = async (manager: EntityManager): Promise<void> => {\n  //1\n  // Add your seeding logic here using the manager\n  // For example:\n\n  await seedUser();\n  await seedArtist();\n  await seedPlayLists();\n\n  async function seedUser() {\n    //2\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    await manager.getRepository(User).save(user);\n  }\n\n  async function seedArtist() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const artist = new Artist();\n    artist.user = user;\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Artist).save(artist);\n  }\n\n  async function seedPlayLists() {\n    const salt = await bcrypt.genSalt();\n    const encryptedPassword = await bcrypt.hash('123456', salt);\n\n    const user = new User();\n    user.firstName = faker.person.firstName();\n    user.lastName = faker.person.lastName();\n    user.email = faker.internet.email();\n    user.password = encryptedPassword;\n    user.apiKey = uuid4();\n\n    const playList = new Playlist();\n    playList.name = faker.music.genre();\n    playList.user = user;\n\n    await manager.getRepository(User).save(user);\n    await manager.getRepository(Playlist).save(playList);\n  }\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/env.validation.ts",
    "content": "import { plainToInstance } from 'class-transformer';\nimport { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';\n\nenum Environment {\n  Development = 'development',\n  Production = 'production',\n  Test = 'test',\n  Provision = 'provision',\n}\n\nclass EnvironmentVariables {\n  @IsEnum(Environment)\n  NODE_ENV: Environment;\n\n  @IsNumber()\n  PORT: number;\n\n  @IsNumber()\n  DB_PORT: number;\n\n  @IsString()\n  DB_HOST: string;\n\n  @IsString()\n  USERNAME: string;\n\n  @IsString()\n  PASSWORD: string;\n\n  @IsString()\n  DB_NAME: string;\n\n  @IsString()\n  SECRET: string;\n}\n\nexport function validate(config: Record<string, unknown>) {\n  // console.log('config ', config);\n  const validatedConfig = plainToInstance(EnvironmentVariables, config, {\n    enableImplicitConversion: true,\n  });\n  // console.log(validatedConfig);\n\n  const errors = validateSync(validatedConfig, {\n    skipMissingProperties: false,\n  });\n\n  if (errors.length > 0) {\n    throw new Error(errors.toString());\n  }\n  return validatedConfig;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"plugins\": [\n      {\n        \"name\": \"@nestjs/swagger\",\n        \"options\": {\n          \"introspectComments\": true\n        }\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest build --webpack --webpackPath webpack-hmr.config.js --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"typeorm\": \"npm run build && npx typeorm -d dist/db/data-source.js\",\n    \"migration:generate\": \"npm run typeorm -- migration:generate\",\n    \"migration:run\": \"npm run typeorm -- migration:run\",\n    \"migration:revert\": \"npm run typeorm -- migration:revert\",\n    \"@nestjs/swagger\": \"^6.3.0\"\n  },\n  \"dependencies\": {\n    \"@faker-js/faker\": \"^8.0.1\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/config\": \"^2.3.2\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/swagger\": \"^6.3.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-http-bearer\": \"^1.0.1\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"speakeasy\": \"^2.0.0\",\n    \"typeorm\": \"^0.3.15\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/speakeasy\": \"^2.0.7\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"run-script-webpack-plugin\": \"^0.2.0\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n{\n\"title\": \"Love again\",\n\"artists\": [1],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john13@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### API KEY JOHN13 TEMP : 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Signup Artist\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"Martin\",\n    \"lastName\": \"Garrix\",\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login Artist\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix1@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Artist Token Temp:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjIsImFydGlzdElkIjoxLCJpYXQiOjE2ODQ5MDkxMTMsImV4cCI6MTY4NDk5NTUxM30.u7vwcccTXkbMIZvg1k0ZOA_dD1TvzZRDbO6xm8w23Bc\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"martingarrix@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Enable 2FA\nGET http://localhost:3000/auth/enable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\n\n### Validate 2FA Token\nPOST http://localhost:3000/auth/validate-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1hcnRpbmdhcnJpeEBnbWFpbC5jb20iLCJ1c2VySWQiOjQ2LCJpYXQiOjE2ODU3ODYzODksImV4cCI6MTY4NTg3Mjc4OX0.dxUxLCYS8YFLGkVXMu85DMJy5ev1CJGj_vP7Qx8v8hA\nContent-Type: application/json\n\n{\n    \"token\": \"993913\"\n}\n\n### Disable 2FA\nGET http://localhost:3000/auth/disable-2fa\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJ1c2VySWQiOjEsImlhdCI6MTY4NDkxMTk3OCwiZXhwIjoxNjg0OTk4Mzc4fQ.qbBHZfu0VL_tY_bC2ccl1I_Xoc0IqG6wAk-D2-tZDa8\n\n\n### Access Profile\nGET http://localhost:3000/auth/profile\nAuthorization: Bearer 17838da8-99a7-443f-89fa-ba7338581ee0\n\n### Test Env\n\nGET http://localhost:3000/auth/test"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/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": "module-12-deploy-nestjs/deployment-starter/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGuard } from './auth/jwt-guard';\nimport { ApiBearerAuth } from '@nestjs/swagger';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGuard)\n  @ApiBearerAuth('JWT-auth') //1\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/app.module.ts",
    "content": "import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { LoggerMiddleware } from './common/middleware/logger.middleware';\nimport { SongsController } from './songs/songs.controller';\nimport { SongsModule } from './songs/songs.module';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { typeOrmAsyncConfig } from 'db/data-source';\nimport { SeedModule } from './seed/seed.module';\nimport { ConfigModule } from '@nestjs/config';\nimport configuration from './config/configuration';\nimport { validate } from 'env.validation';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      envFilePath: ['.env.development', '.env.production'],\n      isGlobal: true,\n      load: [configuration],\n      validate: validate,\n    }),\n    TypeOrmModule.forRootAsync(typeOrmAsyncConfig),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n    ArtistsModule,\n    SeedModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule implements NestModule {\n  constructor(/*private dataSource: DataSource*/) {\n    // console.log('dbName ', dataSource.driver.database);\n  }\n  configure(consumer: MiddlewareConsumer) {\n    // consumer.apply(LoggerMiddleware).forRoutes('songs'); // option no 1\n    // consumer\n    //   .apply(LoggerMiddleware)\n    //   .forRoutes({ path: 'songs', method: RequestMethod.POST }); //option no 2\n\n    consumer.apply(LoggerMiddleware).forRoutes(SongsController); //option no 3\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/artists/artists.controller.ts",
    "content": "import { Controller } from '@nestjs/common';\n\n@Controller('artists')\nexport class ArtistsController {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Artist } from './artist.entity';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Artist])],\n  providers: [ArtistsService],\n  controllers: [ArtistsController],\n  exports: [ArtistsService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { Artist } from './artist.entity';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(\n    @InjectRepository(Artist)\n    private artistRepo: Repository<Artist>,\n  ) {}\n\n  findArtist(userId: number): Promise<Artist> {\n    return this.artistRepo.findOneBy({ user: { id: userId } });\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/api-key-strategy.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Strategy } from 'passport-http-bearer';\nimport { AuthService } from './auth.service';\n\n@Injectable()\nexport class ApiKeyStrategy extends PassportStrategy(Strategy) {\n  constructor(private authService: AuthService) {\n    super();\n  }\n  async validate(apiKey: string) {\n    const user = await this.authService.validateUserByApiKey(apiKey);\n    if (!user) {\n      throw new UnauthorizedException();\n    } else {\n      return user;\n    }\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/artists-jwt-guard.ts",
    "content": "import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class ArtistJwtGuard extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    return super.canActivate(context);\n  }\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw err || new UnauthorizedException();\n    }\n    console.log(user);\n    if (user.artistId) {\n      return user;\n    }\n    throw err || new UnauthorizedException();\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/auth.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Get,\n  Post,\n  Request,\n  UseGuards,\n} from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { JwtAuthGuard } from './jwt-guard';\nimport { Enable2FAType } from './types';\nimport { ValidateTokenDTO } from './dto/validate-token.dto';\nimport { UpdateResult } from 'typeorm';\nimport { AuthGuard } from '@nestjs/passport';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\n@Controller('auth')\n@ApiTags('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  @ApiOperation({ summary: 'Register new user' })\n  @ApiResponse({\n    status: 201,\n    description: 'It will return the user in the response',\n  })\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  @ApiOperation({ summary: 'Login user' })\n  @ApiResponse({\n    status: 200,\n    description: 'It will give you the access_token in the response',\n  })\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n\n  @Get('enable-2fa')\n  @UseGuards(JwtAuthGuard)\n  enable2FA(\n    @Request()\n    req,\n  ): Promise<Enable2FAType> {\n    console.log(req.user);\n    return this.authService.enable2FA(req.user.userId);\n  }\n\n  @Post('validate-2fa')\n  @UseGuards(JwtAuthGuard)\n  validate2FA(\n    @Request()\n    req,\n    @Body()\n    ValidateTokenDTO: ValidateTokenDTO,\n  ): Promise<{ verified: boolean }> {\n    return this.authService.validate2FAToken(\n      req.user.userId,\n      ValidateTokenDTO.token,\n    );\n  }\n  @Get('disable-2fa')\n  @UseGuards(JwtAuthGuard)\n  disable2FA(\n    @Request()\n    req,\n  ): Promise<UpdateResult> {\n    return this.authService.disable2FA(req.user.userId);\n  }\n  @Get('profile')\n  @UseGuards(AuthGuard('bearer'))\n  getProfile(\n    @Request()\n    req,\n  ) {\n    delete req.user.password;\n    return {\n      msg: 'authenticated with api key',\n      user: req.user,\n    };\n  }\n\n  @Get('test')\n  testEnvVariable() {\n    return this.authService.getEnvVariable();\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtStrategy } from './jwt-strategy';\nimport { ArtistsModule } from 'src/artists/artists.module';\nimport { ApiKeyStrategy } from './api-key-strategy';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get<string>('secret'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n    ArtistsModule,\n  ],\n  providers: [AuthService, JwtStrategy, ApiKeyStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\nimport { ArtistsService } from 'src/artists/artists.service';\nimport { Enable2FAType, PayloadType } from './types';\n\nimport * as speakeasy from 'speakeasy';\nimport { UpdateResult } from 'typeorm';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n    private artistsService: ArtistsService,\n    private configService: ConfigService,\n  ) {}\n\n  async login(\n    loginDTO: LoginDTO,\n  ): Promise<\n    { accessToken: string } | { validate2FA: string; message: string }\n  > {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload: PayloadType = { email: user.email, userId: user.id };\n      const artist = await this.artistsService.findArtist(user.id); // 2\n      if (artist) {\n        payload.artistId = artist.id;\n      }\n      if (user.enable2FA && user.twoFASecret) {\n        //1.\n        // sends the validateToken request link\n        // else otherwise sends the json web token in the response\n        return {\n          //2.\n          validate2FA: 'http://localhost:3000/auth/validate-2fa',\n          message:\n            'Please sends the one time password/token from your Google Authenticator App',\n        };\n      }\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n  async enable2FA(userId: number): Promise<Enable2FAType> {\n    const user = await this.userService.findById(userId); //1\n    if (user.enable2FA) {\n      //2\n      return { secret: user.twoFASecret };\n    }\n    const secret = speakeasy.generateSecret(); //3\n    console.log(secret);\n    user.twoFASecret = secret.base32; //4\n    await this.userService.updateSecretKey(user.id, user.twoFASecret); //5\n    return { secret: user.twoFASecret }; //6\n  }\n\n  async validate2FAToken(\n    userId: number,\n    token: string,\n  ): Promise<{ verified: boolean }> {\n    try {\n      // find the user on the based on id\n      const user = await this.userService.findById(userId);\n\n      // extract his 2FA secret\n\n      // verify the secret with token by calling the speakeasy verify method\n      const verified = speakeasy.totp.verify({\n        secret: user.twoFASecret,\n        token: token,\n        encoding: 'base32',\n      });\n\n      // if validated then sends the json web token in the response\n      if (verified) {\n        return { verified: true };\n      } else {\n        return { verified: false };\n      }\n    } catch (err) {\n      throw new UnauthorizedException('Error verifying token');\n    }\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userService.disable2FA(userId);\n  }\n\n  async validateUserByApiKey(apiKey: string): Promise<User> {\n    return this.userService.findByApiKey(apiKey);\n  }\n\n  getEnvVariable() {\n    return this.configService.get<number>('port');\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/dto/validate-token.dto.ts",
    "content": "import { IsNotEmpty, IsString } from 'class-validator';\n\nexport class ValidateTokenDTO {\n  @IsNotEmpty()\n  @IsString()\n  token: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { PayloadType } from './types';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: process.env.SECRET,\n    });\n  }\n\n  async validate(payload: PayloadType) {\n    return {\n      userId: payload.userId,\n      email: payload.email,\n      artistId: payload.artistId,\n    };\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/auth/types.ts",
    "content": "export interface PayloadType {\n  email: string;\n  userId: number;\n  artistId?: number;\n}\n\nexport type Enable2FAType = {\n  secret: string;\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/config/configuration.ts",
    "content": "export default () => ({\n  port: parseInt(process.env.PORT),\n  secret: process.env.SECRET,\n  dbHost: process.env.DB_HOST,\n  dbPort: parseInt(process.env.DB_PORT),\n  username: process.env.USERNAME,\n  password: process.env.PASSWORD,\n  dbName: process.env.DB_NAME,\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\nimport { SeedService } from './seed/seed.service';\nimport { ConfigService } from '@nestjs/config';\nimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';\n\ndeclare const module: any;\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  /**\n   * You can enable the seeding here\n   */\n  // const seedService = app.get(SeedService);\n  // await seedService.seed();\n\n  const config = new DocumentBuilder() //1\n    .setTitle('Spotify Clone')\n    .setDescription('The Spotify Clone Api documentation')\n    .setVersion('1.0')\n    .addBearerAuth(\n      // Enable Bearer Auth here\n      {\n        type: 'http',\n        scheme: 'bearer',\n        bearerFormat: 'JWT',\n        name: 'JWT',\n        description: 'Enter JWT token',\n        in: 'header',\n      },\n      'JWT-auth', // We will use this Bearer Auth with JWT-auth name on the controller function\n    )\n    .build();\n\n  const document = SwaggerModule.createDocument(app, config); //2\n  SwaggerModule.setup('api', app, document); //3\n\n  const configService = app.get(ConfigService);\n  await app.listen(configService.get<number>('port'));\n\n  if (module.hot) {\n    module.hot.accept();\n    module.hot.dispose(() => app.close());\n  }\n}\nbootstrap();\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\nimport { ApiTags } from '@nestjs/swagger';\n\n@Controller('playlists')\n@ApiTags('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/seed/seed.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SeedService } from './seed.service';\n\n@Module({\n  providers: [SeedService],\n})\nexport class SeedModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/seed/seed.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { DataSource } from 'typeorm';\nimport { seedData } from '../../db/seeds/seed-data';\n\n@Injectable()\nexport class SeedService {\n  constructor(private readonly connection: DataSource) {}\n\n  async seed(): Promise<void> {\n    const queryRunner = this.connection.createQueryRunner(); //1\n\n    await queryRunner.connect(); //2\n    await queryRunner.startTransaction(); //3\n\n    try {\n      const manager = queryRunner.manager;\n      await seedData(manager);\n\n      await queryRunner.commitTransaction(); //4\n    } catch (err) {\n      console.log('Error during database seeding:', err);\n      await queryRunner.rollbackTransaction(); // 5\n    } finally {\n      await queryRunner.release(); //6\n    }\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n  UseGuards,\n  Request,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\nimport { ArtistJwtGuard } from 'src/auth/artists-jwt-guard';\nimport { ApiTags } from '@nestjs/swagger';\n\n@Controller('songs')\n@ApiTags('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  @UseGuards(ArtistJwtGuard)\n  create(\n    @Body() createSongDTO: CreateSongDTO,\n    @Request()\n    request,\n  ): Promise<Song> {\n    console.log('request.user: ', request.user);\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/users/user.entity.ts",
    "content": "import { ApiProperty } from '@nestjs/swagger';\nimport { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @ApiProperty({\n    example: 'Jane',\n    description: 'provide the firstName of the user',\n  })\n  @Column()\n  firstName: string;\n\n  @ApiProperty({\n    example: 'Doe',\n    description: 'provide the lastName of the user',\n  })\n  @Column()\n  lastName: string;\n\n  @ApiProperty({\n    example: 'jane_doe@gmail.com',\n    description: 'provide the email of the user',\n  })\n  @Column({ unique: true })\n  email: string;\n\n  @ApiProperty({\n    description: 'provide the password of the user',\n  })\n  @Column()\n  @Exclude()\n  password: string;\n\n  @Column({ nullable: true, type: 'text' })\n  twoFASecret: string;\n\n  @Column({ default: false, type: 'boolean' })\n  enable2FA: boolean;\n\n  @Column()\n  apiKey: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository, UpdateResult } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\nimport { v4 as uuid4 } from 'uuid';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const user = new User();\n    user.firstName = userDTO.firstName;\n    user.lastName = userDTO.lastName;\n    user.email = userDTO.email;\n    user.apiKey = uuid4();\n\n    const salt = await bcrypt.genSalt(); // 2.\n    user.password = await bcrypt.hash(userDTO.password, salt); // 3.\n\n    const savedUser = await this.userRepository.save(user);\n    delete savedUser.password;\n    return savedUser;\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n  async findById(id: number): Promise<User> {\n    return this.userRepository.findOneBy({ id: id });\n  }\n  async updateSecretKey(userId, secret: string): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        twoFASecret: secret,\n        enable2FA: true,\n      },\n    );\n  }\n  async disable2FA(userId: number): Promise<UpdateResult> {\n    return this.userRepository.update(\n      { id: userId },\n      {\n        enable2FA: false,\n        twoFASecret: null,\n      },\n    );\n  }\n  async findByApiKey(apiKey: string): Promise<User> {\n    return this.userRepository.findOneBy({ apiKey });\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/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": "module-12-deploy-nestjs/deployment-starter/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-12-deploy-nestjs/deployment-starter/webpack-hmr.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst nodeExternals = require('webpack-node-externals');\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');\n\nmodule.exports = function (options, webpack) {\n  return {\n    ...options,\n    entry: ['webpack/hot/poll?100', options.entry],\n    externals: [\n      nodeExternals({\n        allowlist: ['webpack/hot/poll?100'],\n      }),\n    ],\n    plugins: [\n      ...options.plugins,\n      new webpack.HotModuleReplacementPlugin(),\n      new webpack.WatchIgnorePlugin({\n        paths: [/\\.js$/, /\\.d\\.ts$/],\n      }),\n      new RunScriptWebpackPlugin({\n        name: options.output.filename,\n        autoRestart: false,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-13-testing/end-to-end-testing/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-13-testing/end-to-end-testing/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/package.json",
    "content": "{\n  \"name\": \"testing-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.11.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.16\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/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": "module-13-testing/end-to-end-testing/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { SongModule } from './song/song.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    SongModule,\n  ],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/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": "module-13-testing/end-to-end-testing/test/songs/songs.e2e-spec.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../../src/song/song.entity';\nimport { SongModule } from '../../src/song/song.module';\nimport { Test } from '@nestjs/testing';\nimport * as request from 'supertest';\nimport { CreateSongDTO } from 'src/song/dto/create-song-dto';\nimport { UpdateSongDTO } from 'src/song/dto/update-song-dto';\n\ndescribe('Songs - /songs', () => {\n  let app: INestApplication;\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it(`/GET songs`, async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const results = await request(app.getHttpServer()).get('/songs');\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toHaveLength(1);\n    expect(results.body).toEqual([newSong]);\n  });\n\n  it('/GET songs/:id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const results = await request(app.getHttpServer()).get(\n      `/songs/${newSong.id}`,\n    );\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual(newSong);\n  });\n\n  it('/PUT songs/:id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const updateSongDTO: UpdateSongDTO = { title: 'Wonderful' };\n    const results = await request(app.getHttpServer())\n      .put(`/songs/${newSong.id}`)\n      .send(updateSongDTO as UpdateSongDTO);\n    expect(results.statusCode).toBe(200);\n    expect(results.body.affected).toEqual(1);\n  });\n\n  it('/POST songs', async () => {\n    const createSongDTO = { title: 'Animals' };\n    const results = await request(app.getHttpServer())\n      .post(`/songs`)\n      .send(createSongDTO as CreateSongDTO);\n    expect(results.status).toBe(201);\n    expect(results.body.title).toBe('Animals');\n  });\n\n  it('/DELETE songs', async () => {\n    const createSongDTO: CreateSongDTO = { title: 'Animals' };\n    const newSong = await createSong(createSongDTO);\n    const results = await request(app.getHttpServer()).delete(\n      `/songs/${newSong.id}`,\n    );\n    expect(results.statusCode).toBe(200);\n    expect(results.body.affected).toBe(1);\n  });\n});\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-13-testing/end-to-end-testing/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-13-testing/jest-basics/.prettierrc",
    "content": "{\"singleQuote\": true}"
  },
  {
    "path": "module-13-testing/jest-basics/mock-function.spec.js",
    "content": "describe('Mock Function Examples', () => {\n  it('should create a basic mock function', () => {\n    const mockFun = jest.fn();\n    mockFun.mockReturnValue(4);\n\n    expect(mockFun()).toBe(4);\n    expect(mockFun()).toBe(4);\n    expect(mockFun.mock.calls.length).toBe(2);\n    expect(mockFun).toHaveBeenCalled();\n  });\n\n  it('should create a mock function with an argument', () => {\n    const mockCreateSong = jest.fn((createSongDTO) => ({\n      ...createSongDTO,\n      id: 1,\n    }));\n    expect(mockCreateSong({ title: 'Lover' })).toEqual({\n      title: 'Lover',\n      id: 1,\n    });\n  });\n\n  it('should create a mock function with an argument with mock implementation', () => {\n    const mockCreateSong = jest.fn();\n    mockCreateSong.mockImplementation((createSongDTO) => ({\n      ...createSongDTO,\n      id: 1,\n    }));\n    expect(mockCreateSong({ title: 'Lover' })).toEqual({\n      title: 'Lover',\n      id: 1,\n    });\n  });\n\n  it('should create a mock function with promise', () => {\n    const fetchSongs = jest.fn();\n    fetchSongs.mockResolvedValue([{ id: 1, title: 'Lover' }]);\n\n    expect(fetchSongs()).resolves.toEqual([{ id: 1, title: 'Lover' }]);\n    expect(fetchSongs()).resolves.toHaveLength(1);\n  });\n});\n"
  },
  {
    "path": "module-13-testing/jest-basics/package.json",
    "content": "{\n  \"scripts\": {\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watchAll\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^29.5.2\",\n    \"jest\": \"^29.5.0\"\n  }\n}\n"
  },
  {
    "path": "module-13-testing/jest-basics/spyon-demon.spec.js",
    "content": "const songRepository = {\n  create: (createSongDTO) => {\n    // Original method implementation\n  },\n  find: () => {},\n  findOne: (id) => {},\n};\n\nclass ArtistRepository {\n  save(createArtistDTO) {\n    // Original method implementation\n  }\n}\n\ndescribe('spyOn Demo', () => {\n  it('should spyon the existing object method', () => {\n    const spy = jest.spyOn(songRepository, 'create'); //1\n    songRepository.create({ title: 'Lover' });\n\n    console.log(spy.mock.calls.length);\n\n    expect(spy).toHaveBeenCalled();\n    expect(spy).toHaveBeenCalledWith({ title: 'Lover' });\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should spy on the class method', () => {\n    const artist = new ArtistRepository();\n    const spy = jest\n      .spyOn(artist, 'save')\n      .mockImplementation((createArtistDTO) => ({ ...createArtistDTO, id: 1 }));\n\n    // Call the method\n    artist.save({ name: 'Martin Garrix' }); //1\n\n    console.log(spy({ name: 'Martin Garrix' }));\n    // Assertions\n    expect(spy).toHaveBeenCalled();\n    expect(spy).toHaveBeenCalledWith({ name: 'Martin Garrix' });\n    expect(spy.mock.calls.length).toBe(2);\n  });\n\n  afterEach(() => jest.resetAllMocks());\n});\n"
  },
  {
    "path": "module-13-testing/jest-basics/sum.js",
    "content": "function sum(a, b) {\n    return a + b;\n  }\nmodule.exports = sum;"
  },
  {
    "path": "module-13-testing/jest-basics/sum.test.js",
    "content": "const sum = require('./sum');\n\ntest('it should give me the result 1+2 = 3', () => {\n    expect(sum(1, 2)).toBe(3)\n    expect(sum(1,4)).toBe(5)\n})"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/package.json",
    "content": "{\n  \"name\": \"testing-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.11.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.16\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/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": "module-13-testing/unit-test-controller-and-service/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { SongModule } from './song/song.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    SongModule,\n  ],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/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": "module-13-testing/unit-test-controller-and-service/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-controller-and-service/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-13-testing/unit-test-setup/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-13-testing/unit-test-setup/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/package.json",
    "content": "{\n  \"name\": \"testing-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"pg\": \"^8.11.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.16\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/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": "module-13-testing/unit-test-setup/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { SongModule } from './song/song.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    SongModule,\n  ],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\n\ndescribe('SongService', () => {\n  let service: SongService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongService],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/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": "module-13-testing/unit-test-setup/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-13-testing/unit-test-setup/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-14-websocket/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-14-websocket/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-14-websocket/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-14-websocket/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/package.json",
    "content": "{\n  \"name\": \"websocket-impl\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/platform-socket.io\": \"^10.0.3\",\n    \"@nestjs/websockets\": \"^10.0.3\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/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": "module-14-websocket/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World from nestjs version 10';\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-14-websocket/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-14-websocket/lesson-01/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": "module-14-websocket/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-14-websocket/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-14-websocket/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-14-websocket/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/package.json",
    "content": "{\n  \"name\": \"websocket-impl\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/platform-socket.io\": \"^10.0.3\",\n    \"@nestjs/websockets\": \"^10.0.3\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/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": "module-14-websocket/lesson-02/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World from nestjs version 10';\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/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": "module-14-websocket/lesson-02/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/package.json",
    "content": "{\n  \"name\": \"websocket-impl\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/platform-socket.io\": \"^10.0.3\",\n    \"@nestjs/websockets\": \"^10.0.3\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/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": "module-14-websocket/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { EventsModule } from './events/events.module';\n\n@Module({\n  controllers: [AppController],\n  providers: [AppService],\n  imports: [EventsModule],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World from nestjs version 10';\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/src/events/events.gateway.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { EventsGateway } from './events.gateway';\n\ndescribe('EventsGateway', () => {\n  let gateway: EventsGateway;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [EventsGateway],\n    }).compile();\n\n    gateway = module.get<EventsGateway>(EventsGateway);\n  });\n\n  it('should be defined', () => {\n    expect(gateway).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-14-websocket/lesson-02/src/events/events.gateway.ts",
    "content": "import { OnModuleInit } from '@nestjs/common';\nimport {\n  MessageBody,\n  SubscribeMessage,\n  WebSocketGateway,\n  WebSocketServer,\n} from '@nestjs/websockets';\nimport { Server } from 'socket.io';\n\n@WebSocketGateway({\n  //1\n  cors: {\n    origin: '*',\n  },\n})\nexport class EventsGateway implements OnModuleInit {\n  @WebSocketServer() //2\n  server: Server;\n\n  onModuleInit() {\n    //3\n    this.server.on('connection', (socket) => {\n      console.log(socket.id);\n      console.log(socket.connected);\n    });\n  }\n\n  @SubscribeMessage('message')\n  handleMessage(\n    @MessageBody()\n    data: any,\n  ) {\n    console.log('Message receieved from the client ');\n    console.log(data);\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/src/events/events.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { EventsGateway } from './events.gateway';\n\n@Module({\n  providers: [EventsGateway]\n})\nexport class EventsModule {}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-14-websocket/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-14-websocket/lesson-02/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": "module-14-websocket/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-14-websocket/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-14-websocket/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-14-websocket/lesson-03/.vscode/settings.json",
    "content": "{\n  \"liveServer.settings.port\": 5501\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-14-websocket/lesson-03/client/index.html",
    "content": "<html>\n  <head>\n    <body>\n      <p>Please check the console for the message reply</p>\n    </body>\n    <script\n      src=\"https://cdn.socket.io/4.3.2/socket.io.min.js\"\n      integrity=\"sha384-KAZ4DtjNhLChOB/hxXuKqhMLYvx3b5MlT55xPEiNmREKRzeEm+RVPlTnAn0ajQNs\"\n      crossorigin=\"anonymous\"\n    ></script>\n    <script>\n      const socket = io('http://localhost:3000');\n      socket.on('connect', function () {\n        console.log('Connected');\n        // Send Message to Websocket Server\n        socket.emit('message', { msg: 'I am the client' });\n      });\n\n      socket.on('message', function (data) {\n        console.log('event ', data);\n      });\n      socket.on('exception', function (data) {\n        console.log('event', data);\n      });\n      socket.on('disconnect', function () {\n        console.log('Disconnected');\n      });\n    </script>\n  </head>\n\n  <body></body>\n</html>\n"
  },
  {
    "path": "module-14-websocket/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/package.json",
    "content": "{\n  \"name\": \"websocket-impl\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/platform-socket.io\": \"^10.0.3\",\n    \"@nestjs/websockets\": \"^10.0.3\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/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": "module-14-websocket/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { EventsModule } from './events/events.module';\n\n@Module({\n  controllers: [AppController],\n  providers: [AppService],\n  imports: [EventsModule],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World from nestjs version 10';\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/src/events/events.gateway.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { EventsGateway } from './events.gateway';\n\ndescribe('EventsGateway', () => {\n  let gateway: EventsGateway;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [EventsGateway],\n    }).compile();\n\n    gateway = module.get<EventsGateway>(EventsGateway);\n  });\n\n  it('should be defined', () => {\n    expect(gateway).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-14-websocket/lesson-03/src/events/events.gateway.ts",
    "content": "import { OnModuleInit } from '@nestjs/common';\nimport {\n  MessageBody,\n  SubscribeMessage,\n  WebSocketGateway,\n  WebSocketServer,\n  WsResponse,\n} from '@nestjs/websockets';\nimport { Observable, of } from 'rxjs';\nimport { Server } from 'socket.io';\n\n@WebSocketGateway({\n  //1\n  cors: {\n    origin: '*',\n  },\n})\nexport class EventsGateway implements OnModuleInit {\n  @WebSocketServer() //2\n  server: Server;\n\n  onModuleInit() {\n    //3\n    this.server.on('connection', (socket) => {\n      console.log(socket.id);\n      console.log(socket.connected);\n    });\n  }\n\n  @SubscribeMessage('message')\n  handleMessage(\n    @MessageBody()\n    data: any,\n  ): Observable<WsResponse<any>> {\n    console.log('Message receieved from the client ');\n    console.log(data);\n    return of({\n      event: 'message',\n      data: 'MESSAGE RETURNED FROM SERVER: HELLo',\n    });\n  }\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/src/events/events.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { EventsGateway } from './events.gateway';\n\n@Module({\n  providers: [EventsGateway]\n})\nexport class EventsModule {}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-14-websocket/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-14-websocket/lesson-03/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": "module-14-websocket/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-14-websocket/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/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": "module-15-build-graphql-apis/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/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": "module-15-build-graphql-apis/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/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": "module-15-build-graphql-apis/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/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": "module-15-build-graphql-apis/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/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": "module-15-build-graphql-apis/lesson-03-and-04/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongResolver],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    return this.songService.createSong(args);\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n    @Args('id')\n    id: string,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/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": "module-15-build-graphql-apis/lesson-03-and-04/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-03-and-04/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/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": "module-15-build-graphql-apis/lesson-05/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongResolver],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { GraphQLError } from 'graphql';\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    // return this.songService.getSongs();\n    // throw new Error('Unable to fetch songs!');\n    throw new GraphQLError('Unable to fetch the songs', {\n      extensions: {\n        code: 'INTERNAL_SERVER_ERROR',\n      },\n    });\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    return this.songService.createSong(args);\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n    @Args('id')\n    id: string,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/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": "module-15-build-graphql-apis/lesson-05/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-15-build-graphql-apis/lesson-05/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"graphql\": \"^16.7.1\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"^25.0.0\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-morph\": \"^19.0.0\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/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": "module-16-authenticate-graphql-apis/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'graphql-auth',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: ({ req }) => ({ req }),\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.graphql",
    "content": "type User {\n  id: ID!\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ntype Query {\n  login(loginInput: LoginInput!): LoginResponse!\n}\n\ntype Mutation {\n  singup(singupInput: SingupInput!): SignupResponse!\n}\n\ninput SingupInput {\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ninput LoginInput {\n  email: String!\n  password: String!\n}\n\ntype SignupResponse {\n  email: String!\n}\ntype LoginResponse {\n  acessToken: String!\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class SingupInput {\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport class LoginInput {\n    email: string;\n    password: string;\n}\n\nexport class User {\n    id: string;\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport abstract class IQuery {\n    abstract login(loginInput: LoginInput): LoginResponse | Promise<LoginResponse>;\n}\n\nexport abstract class IMutation {\n    abstract singup(singupInput: SingupInput): SignupResponse | Promise<SignupResponse>;\n}\n\nexport class SignupResponse {\n    email: string;\n}\n\nexport class LoginResponse {\n    acessToken: string;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\nimport { AuthService } from 'src/auth/auth.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/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": "module-16-authenticate-graphql-apis/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"graphql\": \"^16.7.1\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"^25.0.0\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-morph\": \"^19.0.0\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/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": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'graphql-auth',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: ({ req }) => ({ req }),\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.graphql",
    "content": "type User {\n  id: ID!\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ntype Query {\n  login(loginInput: LoginInput!): LoginResponse!\n}\n\ntype Mutation {\n  singup(singupInput: SingupInput!): SignupResponse!\n}\n\ninput SingupInput {\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ninput LoginInput {\n  email: String!\n  password: String!\n}\n\ntype SignupResponse {\n  email: String!\n}\ntype LoginResponse {\n  acessToken: String!\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class SingupInput {\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport class LoginInput {\n    email: string;\n    password: string;\n}\n\nexport class User {\n    id: string;\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport abstract class IQuery {\n    abstract login(loginInput: LoginInput): LoginResponse | Promise<LoginResponse>;\n}\n\nexport abstract class IMutation {\n    abstract singup(singupInput: SingupInput): SignupResponse | Promise<SignupResponse>;\n}\n\nexport class SignupResponse {\n    email: string;\n}\n\nexport class LoginResponse {\n    acessToken: string;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\nimport { AuthService } from 'src/auth/auth.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/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": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"graphql\": \"^16.7.1\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"^25.0.0\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-morph\": \"^19.0.0\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/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": "module-16-authenticate-graphql-apis/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'graphql-auth',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: ({ req }) => ({ req }),\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.graphql",
    "content": "type User {\n  id: ID!\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ntype Query {\n  login(loginInput: LoginInput!): LoginResponse!\n}\n\ntype Mutation {\n  signup(signupInput: SignupInput!): SignupResponse!\n}\n\ninput SignupInput {\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ninput LoginInput {\n  email: String!\n  password: String!\n}\n\ntype SignupResponse {\n  email: String!\n}\ntype LoginResponse {\n  accessToken: String!\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { AuthResolver } from './auth.resolver';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy, AuthResolver],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthResolver } from './auth.resolver';\n\ndescribe('AuthResolver', () => {\n  let resolver: AuthResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthResolver],\n    }).compile();\n\n    resolver = module.get<AuthResolver>(AuthResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Query } from '@nestjs/graphql';\nimport {\n  SignupResponse,\n  SignupInput,\n  LoginInput,\n  LoginResponse,\n} from 'src/graphql';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\n\n@Resolver()\nexport class AuthResolver {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n\n  @Mutation('signup')\n  singupUser(\n    @Args('signupInput')\n    signupInput: SignupInput,\n  ): Promise<SignupResponse> {\n    return this.userService.create(signupInput);\n  }\n  @Query('login')\n  loginUser(\n    @Args('loginInput')\n    loginInput: LoginInput,\n  ): Promise<LoginResponse> {\n    return this.authService.login(loginInput);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class SignupInput {\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport class LoginInput {\n    email: string;\n    password: string;\n}\n\nexport class User {\n    id: string;\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport abstract class IQuery {\n    abstract login(loginInput: LoginInput): LoginResponse | Promise<LoginResponse>;\n}\n\nexport abstract class IMutation {\n    abstract signup(signupInput: SignupInput): SignupResponse | Promise<SignupResponse>;\n}\n\nexport class SignupResponse {\n    email: string;\n}\n\nexport class LoginResponse {\n    accessToken: string;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\nimport { AuthService } from 'src/auth/auth.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/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": "module-16-authenticate-graphql-apis/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/.vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach\",\n      \"port\": 9229,\n      \"request\": \"attach\",\n      \"skipFiles\": [\"<node_internals>/**\"],\n      \"type\": \"node\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"graphql\": \"^16.7.1\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"^25.0.0\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-morph\": \"^19.0.0\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/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": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'graphql-auth',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: ({ req }) => ({ req }),\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.graphql",
    "content": "type User {\n  id: ID!\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ntype Query {\n  login(loginInput: LoginInput!): LoginResponse!\n}\n\ntype Mutation {\n  singup(singupInput: SingupInput!): SignupResponse!\n}\n\ninput SingupInput {\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ninput LoginInput {\n  email: String!\n  password: String!\n}\n\ntype SignupResponse {\n  email: String!\n}\ntype LoginResponse {\n  acessToken: String!\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class SingupInput {\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport class LoginInput {\n    email: string;\n    password: string;\n}\n\nexport class User {\n    id: string;\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport abstract class IQuery {\n    abstract login(loginInput: LoginInput): LoginResponse | Promise<LoginResponse>;\n}\n\nexport abstract class IMutation {\n    abstract singup(singupInput: SingupInput): SignupResponse | Promise<SignupResponse>;\n}\n\nexport class SignupResponse {\n    email: string;\n}\n\nexport class LoginResponse {\n    acessToken: string;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\nimport { AuthService } from 'src/auth/auth.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/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": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"graphql\": \"^16.7.1\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"^25.0.0\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-morph\": \"^19.0.0\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/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": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'graphql-auth',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: ({ req }) => ({ req }),\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.graphql",
    "content": "type User {\n  id: ID!\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ntype Query {\n  login(loginInput: LoginInput!): LoginResponse!\n}\n\ntype Mutation {\n  signup(signupInput: SignupInput!): SignupResponse!\n}\n\ninput SignupInput {\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ninput LoginInput {\n  email: String!\n  password: String!\n}\n\ntype SignupResponse {\n  email: String!\n}\ntype LoginResponse {\n  accessToken: String!\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { AuthResolver } from './auth.resolver';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy, AuthResolver],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthResolver } from './auth.resolver';\n\ndescribe('AuthResolver', () => {\n  let resolver: AuthResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthResolver],\n    }).compile();\n\n    resolver = module.get<AuthResolver>(AuthResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Query } from '@nestjs/graphql';\nimport {\n  SignupResponse,\n  SignupInput,\n  LoginInput,\n  LoginResponse,\n} from 'src/graphql';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\n\n@Resolver()\nexport class AuthResolver {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n\n  @Mutation('signup')\n  singupUser(\n    @Args('signupInput')\n    signupInput: SignupInput,\n  ): Promise<SignupResponse> {\n    return this.userService.create(signupInput);\n  }\n  @Query('login')\n  loginUser(\n    @Args('loginInput')\n    loginInput: LoginInput,\n  ): Promise<LoginResponse> {\n    return this.authService.login(loginInput);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class SignupInput {\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport class LoginInput {\n    email: string;\n    password: string;\n}\n\nexport class User {\n    id: string;\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport abstract class IQuery {\n    abstract login(loginInput: LoginInput): LoginResponse | Promise<LoginResponse>;\n}\n\nexport abstract class IMutation {\n    abstract signup(signupInput: SignupInput): SignupResponse | Promise<SignupResponse>;\n}\n\nexport class SignupResponse {\n    email: string;\n}\n\nexport class LoginResponse {\n    accessToken: string;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\nimport { AuthService } from 'src/auth/auth.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/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": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/package.json",
    "content": "{\n  \"name\": \"n-fundamentals-pro\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/jwt\": \"^10.0.3\",\n    \"@nestjs/passport\": \"^9.0.3\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/typeorm\": \"^9.0.1\",\n    \"bcryptjs\": \"^2.4.3\",\n    \"class-transformer\": \"^0.5.1\",\n    \"class-validator\": \"^0.14.0\",\n    \"graphql\": \"^16.7.1\",\n    \"nestjs-typeorm-paginate\": \"^4.0.3\",\n    \"passport\": \"^0.6.0\",\n    \"passport-jwt\": \"^4.0.1\",\n    \"pg\": \"^8.10.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"typeorm\": \"^0.3.15\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/bcryptjs\": \"^2.4.2\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/passport-jwt\": \"^3.0.8\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"^25.0.0\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-morph\": \"^19.0.0\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/rest-client.http",
    "content": "GET http://localhost:3000\n\n### SEND FETCH SONGS REQUEST\nGET http://localhost:3000/songs/?page=1&limit=2\n\n### Find SONGS REQUEST\nGET http://localhost:3000/songs/1\n\n### Create New SONGS REQUEST\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n\"title\": \"You for me 3\",\n\"artists\": [1,2],\n\"releasedDate\" : \"2023-05-11\",\n\"duration\" :\"02:34\",\n\"lyrics\": \"Sby, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n\n### Update SONGS REQUEST\nPUT http://localhost:3000/songs/2\nContent-Type: application/json\n\n{\n\"title\": \"Animals\",\n\"artists\": [\n    \"Martin\"\n],\n\"releasedDate\" : \"2023-02-02\",\n\"duration\" :\"03:43\",\n\"lyrics\": \"ANIM, you're my adrenaline. Brought out this other side of me You don't even know Controlling my whole anatomy, oh Fingers are holding you right at the edge You're slipping out of my hands Keeping my secrets all up in my head I'm scared that you won't want me back, oh I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya I wish that I was honest when I had you I shoulda told you that I wanted you for me I dance to every song like it's about ya I drink 'til I kiss someone who looks like ya\"\n}\n\n### Update SONGS REQUEST\nDELETE http://localhost:3000/songs/1\n\n\n### Create new PlayList\n\nPOST http://localhost:3000/playlists\nContent-Type: application/json\n\n{\n    \"name\": \"Feel Good Now\",\n    \"songs\": [\n        6\n    ],\n    \"user\": 2\n}\n\n### Signup User\n\nPOST http://localhost:3000/auth/signup\nContent-Type: application/json\n\n{\n    \"firstName\": \"john\",\n    \"lastName\": \"doe\",\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n### Login User\n\nPOST http://localhost:3000/auth/login\nContent-Type: application/json\n\n{\n    \"email\": \"john12@gmail.com\",\n    \"password\": \"123456\"\n}\n\n## Access TOKEN : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n### Profile\n\nGET http://localhost:3000/profile\nAuthorization: Bearer  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4xMkBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY4NDg1NTYyMSwiZXhwIjoxNjg0OTQyMDIxfQ.4FAABSVzS_6NUAjldhn7-EZ0UbAUUfKgGZ0Qv4tma7M\n\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/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": "module-16-authenticate-graphql-apis/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get, Req, UseGuards } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { JwtAuthGaurd } from './auth/jwt-guard';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('profile')\n  @UseGuards(JwtAuthGaurd)\n  getProfile(\n    @Req()\n    request,\n  ) {\n    return request.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { Song } from './songs/song.entity';\nimport { Artist } from './artists/artist.entity';\nimport { User } from './users/user.entity';\nimport { Playlist } from './playlists/playlist.entity';\nimport { PlayListModule } from './playlists/playlists.module';\n// import { DataSource } from 'typeorm';\nimport { AuthModule } from './auth/auth.module';\nimport { UsersModule } from './users/users.module';\n\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      database: 'graphql-auth',\n      host: 'localhost',\n      port: 5432,\n      username: 'postgres',\n      password: 'root',\n      entities: [Song, Artist, User, Playlist],\n      synchronize: true,\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: ({ req }) => ({ req }),\n    }),\n    SongsModule,\n    PlayListModule,\n    AuthModule,\n    UsersModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/app.service.ts",
    "content": "import { Inject, Injectable } from '@nestjs/common';\nimport { DevConfigService } from './common/providers/DevConfigService';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello I am learning Nest.js Fundamentals';\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/artists/artist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Entity,\n  JoinColumn,\n  ManyToMany,\n  OneToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('artists')\nexport class Artist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @OneToOne(() => User)\n  @JoinColumn()\n  user: User;\n\n  @ManyToMany(() => Song, (song) => song.artists)\n  songs: Song[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.constants.ts",
    "content": "export const authConstants = {\n  secret: 'HAD_12X#@',\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthController } from './auth.controller';\n\ndescribe('AuthController', () => {\n  let controller: AuthController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AuthController],\n    }).compile();\n\n    controller = module.get<AuthController>(AuthController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { CreateUserDTO } from 'src/users/dto/create-user.dto';\nimport { User } from 'src/users/user.entity';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { LoginDTO } from './dto/login.dto';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n  @Post('signup')\n  signup(\n    @Body()\n    userDTO: CreateUserDTO,\n  ): Promise<User> {\n    return this.userService.create(userDTO);\n  }\n\n  @Post('login')\n  login(\n    @Body()\n    loginDTO: LoginDTO,\n  ) {\n    return this.authService.login(loginDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.graphql",
    "content": "type User {\n  id: ID!\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ntype Query {\n  login(loginInput: LoginInput!): LoginResponse!\n  profile: Profile!\n}\n\ntype Mutation {\n  signup(signupInput: SignupInput!): SignupResponse!\n}\n\ntype Profile {\n  email: String!\n  userId: String!\n}\n\ninput SignupInput {\n  firstName: String!\n  lastName: String!\n  email: String!\n  password: String!\n}\n\ninput LoginInput {\n  email: String!\n  password: String!\n}\n\ntype SignupResponse {\n  email: String!\n}\ntype LoginResponse {\n  accessToken: String!\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AuthService } from './auth.service';\nimport { AuthController } from './auth.controller';\nimport { UsersModule } from 'src/users/users.module';\nimport { JwtModule } from '@nestjs/jwt';\nimport { authConstants } from './auth.constants';\nimport { JwtStrategy } from './jwt-strategy';\nimport { AuthResolver } from './auth.resolver';\n\n@Module({\n  imports: [\n    UsersModule,\n    JwtModule.register({\n      secret: authConstants.secret,\n      signOptions: {\n        expiresIn: '1d',\n      },\n    }),\n  ],\n  providers: [AuthService, JwtStrategy, AuthResolver],\n  controllers: [AuthController],\n  exports: [AuthService],\n})\nexport class AuthModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthResolver } from './auth.resolver';\n\ndescribe('AuthResolver', () => {\n  let resolver: AuthResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthResolver],\n    }).compile();\n\n    resolver = module.get<AuthResolver>(AuthResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Query } from '@nestjs/graphql';\nimport {\n  SignupResponse,\n  SignupInput,\n  LoginInput,\n  LoginResponse,\n  Profile,\n} from 'src/graphql';\nimport { UsersService } from 'src/users/users.service';\nimport { AuthService } from './auth.service';\nimport { UseGuards } from '@nestjs/common';\nimport { GraphQLAuthGaurd } from './gql-auth-guard';\n\n@Resolver()\nexport class AuthResolver {\n  constructor(\n    private userService: UsersService,\n    private authService: AuthService,\n  ) {}\n\n  @Mutation('signup')\n  singupUser(\n    @Args('signupInput')\n    signupInput: SignupInput,\n  ): Promise<SignupResponse> {\n    return this.userService.create(signupInput);\n  }\n  @Query('login')\n  loginUser(\n    @Args('loginInput')\n    loginInput: LoginInput,\n  ): Promise<LoginResponse> {\n    return this.authService.login(loginInput);\n  }\n\n  @Query('profile')\n  @UseGuards(GraphQLAuthGaurd)\n  getProfile(parent, args, contextValue, info): Profile {\n    console.log(parent);\n    console.log(args);\n    console.log(contextValue);\n    console.log(info);\n    return contextValue.req.user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AuthService } from './auth.service';\n\ndescribe('AuthService', () => {\n  let service: AuthService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AuthService],\n    }).compile();\n\n    service = module.get<AuthService>(AuthService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/auth.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { UsersService } from 'src/users/users.service';\nimport { LoginDTO } from './dto/login.dto';\nimport { User } from 'src/users/user.entity';\nimport * as bcrypt from 'bcryptjs';\nimport { JwtService } from '@nestjs/jwt';\n\n@Injectable()\nexport class AuthService {\n  constructor(\n    private userService: UsersService,\n    private jwtService: JwtService,\n  ) {}\n\n  async login(loginDTO: LoginDTO): Promise<{ accessToken: string }> {\n    const user = await this.userService.findOne(loginDTO); // 1.\n\n    const passwordMatched = await bcrypt.compare(\n      loginDTO.password,\n      user.password,\n    );\n\n    if (passwordMatched) {\n      delete user.password;\n      const payload = { email: user.email, sub: user.id };\n\n      return {\n        accessToken: this.jwtService.sign(payload),\n      };\n    } else {\n      throw new UnauthorizedException('Password does not match'); // 5.\n    }\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/dto/login.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class LoginDTO {\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/gql-auth-guard.ts",
    "content": "import { AuthenticationError } from '@nestjs/apollo';\nimport { ExecutionContext, Injectable } from '@nestjs/common';\nimport { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';\nimport { GqlExecutionContext } from '@nestjs/graphql';\nimport { AuthGuard } from '@nestjs/passport';\nimport { Observable } from 'rxjs';\n\n@Injectable()\nexport class GraphQLAuthGaurd extends AuthGuard('jwt') {\n  canActivate(\n    context: ExecutionContext,\n  ): boolean | Promise<boolean> | Observable<boolean> {\n    const ctx = GqlExecutionContext.create(context);\n    const { req } = ctx.getContext();\n    return super.canActivate(new ExecutionContextHost([req]));\n  }\n\n  handleRequest<TUser = any>(err: any, user: any): TUser {\n    if (err || !user) {\n      throw new AuthenticationError('GqlAuthguard');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/jwt-guard.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport';\n\n@Injectable()\nexport class JwtAuthGaurd extends AuthGuard('jwt') {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/auth/jwt-strategy.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\nimport { authConstants } from './auth.constants';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor() {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: authConstants.secret,\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/common/constatnts/connection.ts",
    "content": "export const connection: Connection = {\n  CONNECTION_STRING: 'MYSQL://12324/sad',\n  DB: 'MYSQL',\n  DBNAME: 'TEST',\n};\nexport type Connection = {\n  CONNECTION_STRING: string;\n  DB: string;\n  DBNAME: string;\n};\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/common/middleware/logger.middleware.ts",
    "content": "import { Injectable, NestMiddleware } from '@nestjs/common';\n\n@Injectable()\nexport class LoggerMiddleware implements NestMiddleware {\n  use(req: any, res: any, next: () => void) {\n    console.log('Request ....', new Date().toDateString());\n    next();\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/common/providers/DevConfigService.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class DevConfigService {\n  DBHOST = 'localhost';\n  getDBHOST() {\n    return this.DBHOST;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class SignupInput {\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport class LoginInput {\n    email: string;\n    password: string;\n}\n\nexport class User {\n    id: string;\n    firstName: string;\n    lastName: string;\n    email: string;\n    password: string;\n}\n\nexport abstract class IQuery {\n    abstract login(loginInput: LoginInput): LoginResponse | Promise<LoginResponse>;\n\n    abstract profile(): Profile | Promise<Profile>;\n}\n\nexport abstract class IMutation {\n    abstract signup(signupInput: SignupInput): SignupResponse | Promise<SignupResponse>;\n}\n\nexport class Profile {\n    email: string;\n    userId: string;\n}\n\nexport class SignupResponse {\n    email: string;\n}\n\nexport class LoginResponse {\n    accessToken: string;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ValidationPipe } from '@nestjs/common';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/playlists/dto/create-playlist.dto.ts",
    "content": "import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';\n\nexport class CreatePlayListDto {\n  @IsString()\n  @IsNotEmpty()\n  readonly name;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly songs;\n\n  @IsNumber()\n  @IsNotEmpty()\n  readonly user: number;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/playlists/playlist.entity.ts",
    "content": "import { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\nimport {\n  Column,\n  Entity,\n  ManyToOne,\n  OneToMany,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('playlists')\nexport class Playlist {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  name: string;\n\n  /**\n   * Each Playlist will have multiple songs\n   */\n  @OneToMany(() => Song, (song) => song.playList)\n  songs: Song[];\n\n  /**\n   * Many Playlist can belong to a single unique user\n   */\n\n  @ManyToOne(() => User, (user) => user.playLists)\n  user: User;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/playlists/playlists.controller.ts",
    "content": "import { Body, Controller, Post } from '@nestjs/common';\nimport { Playlist } from './playlist.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\nimport { PlayListsService } from './playlists.service';\n\n@Controller('playlists')\nexport class PlayListsController {\n  constructor(private playListService: PlayListsService) {}\n  @Post()\n  create(\n    @Body()\n    playlistDTO: CreatePlayListDto,\n  ): Promise<Playlist> {\n    return this.playListService.create(playlistDTO);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/playlists/playlists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PlayListsController } from './playlists.controller';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { PlayListsService } from './playlists.service';\nimport { Song } from 'src/songs/song.entity';\nimport { User } from 'src/users/user.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Playlist, Song, User])],\n  controllers: [PlayListsController],\n  providers: [PlayListsService],\n})\nexport class PlayListModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/playlists/playlists.service.ts",
    "content": "import { InjectRepository } from '@nestjs/typeorm';\nimport { Playlist } from './playlist.entity';\nimport { Song } from 'src/songs/song.entity';\nimport { Injectable } from '@nestjs/common';\nimport { Repository } from 'typeorm';\nimport { User } from 'src/users/user.entity';\nimport { CreatePlayListDto } from './dto/create-playlist.dto';\n\n@Injectable()\nexport class PlayListsService {\n  constructor(\n    @InjectRepository(Playlist)\n    private playListRepo: Repository<Playlist>,\n\n    @InjectRepository(Song)\n    private songsRepo: Repository<Song>,\n\n    @InjectRepository(User)\n    private userRepo: Repository<User>,\n  ) {}\n\n  async create(playListDTO: CreatePlayListDto): Promise<Playlist> {\n    const playList = new Playlist();\n    playList.name = playListDTO.name;\n\n    // songs will be the array of ids that we are getting from the DTO object\n    const songs = await this.songsRepo.findByIds(playListDTO.songs);\n    // set the relation for the songs with playlist entity\n    playList.songs = songs;\n\n    // A user will be the id of the user we are getting from the request\n    // when we implemented the user authentication this id will become the loggedIn user id\n    const user = await this.userRepo.findOneBy({ id: playListDTO.user });\n    playList.user = user;\n\n    return this.playListRepo.save(playList);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/dto/create-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNotEmpty,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class CreateSongDTO {\n  @IsString()\n  @IsNotEmpty()\n  readonly title;\n\n  @IsNotEmpty()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsNotEmpty()\n  @IsDateString()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsNotEmpty()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/dto/update-song-dto.ts",
    "content": "import {\n  IsArray,\n  IsDateString,\n  IsMilitaryTime,\n  IsNumber,\n  IsOptional,\n  IsString,\n} from 'class-validator';\n\nexport class UpdateSongDto {\n  @IsString()\n  @IsOptional()\n  readonly title;\n\n  @IsOptional()\n  @IsArray()\n  @IsNumber({}, { each: true })\n  readonly artists;\n\n  @IsDateString()\n  @IsOptional()\n  readonly releasedDate: Date;\n\n  @IsMilitaryTime()\n  @IsOptional()\n  readonly duration: Date;\n\n  @IsString()\n  @IsOptional()\n  readonly lyrics: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/song.entity.ts",
    "content": "import { Artist } from 'src/artists/artist.entity';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport {\n  Column,\n  Entity,\n  JoinTable,\n  ManyToMany,\n  ManyToOne,\n  PrimaryGeneratedColumn,\n} from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  title: string;\n\n  // @Column('varchar', { array: true })\n  // artists: string[];\n\n  @Column('date')\n  releasedDate: Date;\n\n  @Column('time')\n  duration: Date;\n\n  @Column('text')\n  lyrics: string;\n\n  @ManyToMany(() => Artist, (artist) => artist.songs, { cascade: true })\n  @JoinTable({ name: 'songs_artists' })\n  artists: Artist[];\n\n  /**\n   * Many songs can belong to playlist for each unique user\n   */\n  @ManyToOne(() => Playlist, (playList) => playList.songs)\n  playList: Playlist;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Put,\n  Delete,\n  Post,\n  HttpException,\n  HttpStatus,\n  Param,\n  ParseIntPipe,\n  Body,\n  Inject,\n  Scope,\n  Query,\n  DefaultValuePipe,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { Song } from './song.entity';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Pagination } from 'nestjs-typeorm-paginate';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songsService: SongsService) {}\n  @Post()\n  create(@Body() createSongDTO: CreateSongDTO): Promise<Song> {\n    return this.songsService.create(createSongDTO);\n  }\n  @Get()\n  findAll(\n    @Query('page', new DefaultValuePipe(1), ParseIntPipe)\n    page = 1,\n    @Query('limit', new DefaultValuePipe(10), ParseIntPipe)\n    limit = 10,\n  ): Promise<Pagination<Song>> {\n    limit = limit > 100 ? 100 : limit;\n    return this.songsService.paginate({\n      page,\n      limit,\n    });\n  }\n\n  @Get(':id')\n  findOne(\n    @Param(\n      'id',\n      new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }),\n    )\n    id: number,\n  ): Promise<Song> {\n    return this.songsService.findOne(id);\n  }\n\n  @Put(':id')\n  update(\n    @Param('id', ParseIntPipe) id: number,\n    @Body() updateSongDTO: UpdateSongDto,\n  ): Promise<UpdateResult> {\n    return this.songsService.update(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  delete(@Param('id', ParseIntPipe) id: number): Promise<DeleteResult> {\n    return this.songsService.remove(id);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song, Artist])],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/songs/songs.service.ts",
    "content": "import { ConsoleLogger, Injectable } from '@nestjs/common';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport {\n  paginate,\n  Pagination,\n  IPaginationOptions,\n} from 'nestjs-typeorm-paginate';\n\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { UpdateSongDto } from './dto/update-song-dto';\nimport { Artist } from 'src/artists/artist.entity';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectRepository(Song)\n    private songsRepository: Repository<Song>,\n    @InjectRepository(Artist)\n    private artistsRepository: Repository<Artist>,\n  ) {}\n\n  async create(songDTO: CreateSongDTO): Promise<Song> {\n    const song = new Song();\n    song.title = songDTO.title;\n    song.artists = songDTO.artists;\n    song.duration = songDTO.duration;\n    song.lyrics = songDTO.lyrics;\n    song.releasedDate = songDTO.releasedDate;\n\n    console.log(songDTO.artists);\n\n    // find all the artits on the based on ids\n    const artists = await this.artistsRepository.findByIds(songDTO.artists);\n    console.log(artists);\n    //set the relation with artist and songs\n    song.artists = artists;\n\n    return this.songsRepository.save(song);\n  }\n\n  findAll(): Promise<Song[]> {\n    return this.songsRepository.find();\n  }\n\n  findOne(id: number): Promise<Song> {\n    return this.songsRepository.findOneBy({ id });\n  }\n\n  remove(id: number): Promise<DeleteResult> {\n    return this.songsRepository.delete(id);\n  }\n\n  update(id: number, recordToUpdate: UpdateSongDto): Promise<UpdateResult> {\n    return this.songsRepository.update(id, recordToUpdate);\n  }\n\n  async paginate(options: IPaginationOptions): Promise<Pagination<Song>> {\n    const queryBuilder = this.songsRepository.createQueryBuilder('c');\n    queryBuilder.orderBy('c.releasedDate', 'DESC');\n\n    return paginate<Song>(queryBuilder, options);\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/users/dto/create-user.dto.ts",
    "content": "import { IsEmail, IsNotEmpty, IsString } from 'class-validator';\n\nexport class CreateUserDTO {\n  @IsString()\n  @IsNotEmpty()\n  firstName: string;\n\n  @IsString()\n  @IsNotEmpty()\n  lastName: string;\n\n  @IsEmail()\n  @IsNotEmpty()\n  email: string;\n\n  @IsString()\n  @IsNotEmpty()\n  password: string;\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/users/user.entity.ts",
    "content": "import { Exclude } from 'class-transformer';\nimport { Playlist } from 'src/playlists/playlist.entity';\nimport { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('users')\nexport class User {\n  @PrimaryGeneratedColumn()\n  id: number;\n\n  @Column()\n  firstName: string;\n\n  @Column()\n  lastName: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column()\n  @Exclude()\n  password: string;\n\n  /**\n   * A user can create many playLists\n   */\n  @OneToMany(() => Playlist, (playList) => playList.user)\n  playLists: Playlist[];\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\nimport { AuthService } from 'src/auth/auth.service';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([User])],\n  providers: [UsersService],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/src/users/users.service.ts",
    "content": "import { Injectable, UnauthorizedException } from '@nestjs/common';\nimport { User } from './user.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { Repository } from 'typeorm';\nimport { CreateUserDTO } from './dto/create-user.dto';\nimport * as bcrypt from 'bcryptjs';\nimport { LoginDTO } from 'src/auth/dto/login.dto';\n\n@Injectable()\nexport class UsersService {\n  constructor(\n    @InjectRepository(User)\n    private userRepository: Repository<User>, // 1.\n  ) {}\n\n  async create(userDTO: CreateUserDTO): Promise<User> {\n    const salt = await bcrypt.genSalt(); // 2.\n    userDTO.password = await bcrypt.hash(userDTO.password, salt); // 3.\n    const user = await this.userRepository.save(userDTO); // 4.\n    delete user.password; // 5.\n    return user; // 6.\n  }\n\n  async findOne(data: LoginDTO): Promise<User> {\n    const user = await this.userRepository.findOneBy({ email: data.email });\n    if (!user) {\n      throw new UnauthorizedException('Could not find user');\n    }\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/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": "module-16-authenticate-graphql-apis/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-16-authenticate-graphql-apis/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-17-subscription/subscription-finish/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-17-subscription/subscription-finish/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"graphql-subscriptions\": \"^2.0.0\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/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": "module-17-subscription/subscription-finish/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      installSubscriptionHandlers: true,\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport abstract class ISubscription {\n    abstract songCreated(): Song | Promise<Song>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ntype Subscription {\n  songCreated: Song!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongResolver],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Subscription } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { GraphQLError } from 'graphql';\nimport { PubSub } from 'graphql-subscriptions';\n\nconst pubSub = new PubSub();\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    // return this.songService.getSongs();\n    // throw new Error('Unable to fetch songs!');\n    throw new GraphQLError('Unable to fetch the songs', {\n      extensions: {\n        code: 'INTERNAL_SERVER_ERROR',\n      },\n    });\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    const newSong = this.songService.createSong(args);\n    pubSub.publish('songCreated', { songCreated: newSong });\n    return newSong;\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n    @Args('id')\n    id: string,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n\n  @Subscription('songCreated')\n  songCreated() {\n    return pubSub.asyncIterator('songCreated'); //1\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/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": "module-17-subscription/subscription-finish/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-finish/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-17-subscription/subscription-starter/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-17-subscription/subscription-starter/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/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": "module-17-subscription/subscription-starter/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongResolver],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { GraphQLError } from 'graphql';\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    // return this.songService.getSongs();\n    // throw new Error('Unable to fetch songs!');\n    throw new GraphQLError('Unable to fetch the songs', {\n      extensions: {\n        code: 'INTERNAL_SERVER_ERROR',\n      },\n    });\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    return this.songService.createSong(args);\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n    @Args('id')\n    id: string,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/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": "module-17-subscription/subscription-starter/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-17-subscription/subscription-starter/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"graphql-subscriptions\": \"^2.0.0\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/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": "module-18-testing-graphql-apis/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      installSubscriptionHandlers: true,\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport abstract class ISubscription {\n    abstract songCreated(): Song | Promise<Song>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ntype Subscription {\n  songCreated: Song!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\nimport { SongService } from '../../src/song/song.service';\nimport { CreateSongInput, UpdateSongInput } from '../../src/graphql';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongResolver,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 'a uuid', title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongInput: CreateSongInput) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongInput });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation(\n                (id, string, updateSongInput: UpdateSongInput) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n\n  it('should fetch the songs', async () => {\n    const songs = await resolver.getSongs();\n    expect(songs).toEqual([{ id: 'a uuid', title: 'Dancing Feat' }]);\n    expect(songs.length).toBe(1);\n  });\n\n  it('should create new song', async () => {\n    const song = await resolver.createSong({ title: 'Animals' });\n    expect(song).toEqual({ id: 'a uuid', title: 'Animals' });\n  });\n\n  it('should update the song', async () => {\n    const song = await resolver.updateSong('a uuid', { title: 'DANCING FEAT' });\n    expect(song.affected).toBe(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await resolver.deleteSong('a uuid');\n    expect(song.affected).toBe(1);\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Subscription } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { GraphQLError } from 'graphql';\nimport { PubSub } from 'graphql-subscriptions';\n\nconst pubSub = new PubSub();\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n    // throw new Error('Unable to fetch songs!');\n    // throw new GraphQLError('Unable to fetch the songs', {\n    //   extensions: {\n    //     code: 'INTERNAL_SERVER_ERROR',\n    //   },\n    // });\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    const newSong = this.songService.createSong(args);\n    pubSub.publish('songCreated', { songCreated: newSong });\n    return newSong;\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('id')\n    id: string,\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n\n  @Subscription('songCreated')\n  songCreated() {\n    return pubSub.asyncIterator('songCreated'); //1\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/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": "module-18-testing-graphql-apis/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"graphql-subscriptions\": \"^2.0.0\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/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": "module-18-testing-graphql-apis/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      installSubscriptionHandlers: true,\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport abstract class ISubscription {\n    abstract songCreated(): Song | Promise<Song>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.graphql",
    "content": "type Song {\n  id: ID!\n  title: String\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ntype Subscription {\n  songCreated: Song!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\nimport { SongService } from '../../src/song/song.service';\nimport { CreateSongInput, UpdateSongInput } from '../../src/graphql';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongResolver,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 'a uuid', title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongInput: CreateSongInput) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongInput });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation(\n                (id, string, updateSongInput: UpdateSongInput) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n\n  it('should fetch the songs', async () => {\n    const songs = await resolver.getSongs();\n    expect(songs).toEqual([{ id: 'a uuid', title: 'Dancing Feat' }]);\n    expect(songs.length).toBe(1);\n  });\n\n  it('should create new song', async () => {\n    const song = await resolver.createSong({ title: 'Animals' });\n    expect(song).toEqual({ id: 'a uuid', title: 'Animals' });\n  });\n\n  it('should update the song', async () => {\n    const song = await resolver.updateSong('a uuid', { title: 'DANCING FEAT' });\n    expect(song.affected).toBe(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await resolver.deleteSong('a uuid');\n    expect(song.affected).toBe(1);\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Subscription } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { GraphQLError } from 'graphql';\nimport { PubSub } from 'graphql-subscriptions';\n\nconst pubSub = new PubSub();\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n    // throw new Error('Unable to fetch songs!');\n    // throw new GraphQLError('Unable to fetch the songs', {\n    //   extensions: {\n    //     code: 'INTERNAL_SERVER_ERROR',\n    //   },\n    // });\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    const newSong = this.songService.createSong(args);\n    pubSub.publish('songCreated', { songCreated: newSong });\n    return newSong;\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('id')\n    id: string,\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n\n  @Subscription('songCreated')\n  songCreated() {\n    return pubSub.asyncIterator('songCreated'); //1\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/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": "module-18-testing-graphql-apis/lesson-02/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n});\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-18-testing-graphql-apis/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"generate:typings\": \"ts-node generate-typings\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@apollo/server\": \"^4.7.5\",\n    \"@apollo/server-plugin-response-cache\": \"^4.1.3\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/graphql\": \"^12.0.7\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/typeorm\": \"^10.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"graphql-subscriptions\": \"^2.0.0\",\n    \"pg\": \"^8.11.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\",\n    \"typeorm\": \"^0.3.17\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/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": "module-19-graphql-advanced-concepts/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongModule } from './song/song.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { join } from 'path';\nimport responseCachePlugin from '@apollo/server-plugin-response-cache';\nimport { ApolloServerPluginCacheControl } from '@apollo/server/plugin/cacheControl';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRoot({\n      type: 'postgres',\n      url: 'postgres://postgres:root@localhost:5432/test-dev',\n      synchronize: true,\n      entities: [__dirname + '/**/*.entity.{ts,js}'],\n    }),\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      plugins: [\n        ApolloServerPluginCacheControl({ defaultMaxAge: 5 }),\n        responseCachePlugin(),\n      ],\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      installSubscriptionHandlers: true,\n    }),\n    SongModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport enum CacheControlScope {\n    PUBLIC = \"PUBLIC\",\n    PRIVATE = \"PRIVATE\"\n}\n\nexport class CreateSongInput {\n    title: string;\n}\n\nexport class UpdateSongInput {\n    title?: Nullable<string>;\n}\n\nexport class Song {\n    id: string;\n    title?: Nullable<string>;\n}\n\nexport abstract class IQuery {\n    abstract songs(): Song[] | Promise<Song[]>;\n\n    abstract song(id: string): Song | Promise<Song>;\n}\n\nexport abstract class IMutation {\n    abstract createSong(createSongInput: CreateSongInput): Song | Promise<Song>;\n\n    abstract updateSong(id: string, updateSongInput: UpdateSongInput): UpdateResult | Promise<UpdateResult>;\n\n    abstract deleteSong(id: string): DeleteResult | Promise<DeleteResult>;\n}\n\nexport abstract class ISubscription {\n    abstract songCreated(): Song | Promise<Song>;\n}\n\nexport class UpdateResult {\n    affected: number;\n}\n\nexport class DeleteResult {\n    affected: number;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/dto/create-song-dto.ts",
    "content": "export interface CreateSongDTO {\n  title: string;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/dto/update-song-dto.ts",
    "content": "export interface UpdateSongDTO {\n  title?: string;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongController', () => {\n  let controller: SongController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongController],\n      providers: [\n        SongService,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 1, title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongDTO });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation((updateSongDTO: UpdateSongDTO) => {\n                return Promise.resolve({ affected: 1 });\n              }),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    controller = module.get<SongController>(SongController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n\n  describe('getSongs', () => {\n    it('should fetch all the songs', async () => {\n      const songs = await controller.getSongs();\n      expect(songs).toEqual([{ id: 1, title: 'Dancing Feat' }]);\n    });\n  });\n\n  describe('getSong by id', () => {\n    it('should give me the song by id', async () => {\n      const song = await controller.getSong('a uuid');\n      expect(song.id).toBe('a uuid');\n    });\n  });\n\n  describe('createSong', () => {\n    it('should create a new song', async () => {\n      const newSongDTO: CreateSongDTO = {\n        title: 'Runaway',\n      };\n      const song = await controller.createSong(newSongDTO);\n      expect(song.title).toBe('Runaway');\n      expect(song).toEqual({ id: 'a uuid', title: 'Runaway' });\n    });\n  });\n\n  describe('updateSong', () => {\n    it('should update the song DTO', async () => {\n      const updatesongDTO: UpdateSongDTO = {\n        title: 'Animals',\n      };\n      const updateResults = await controller.updateSong(\n        'a uuid',\n        updatesongDTO,\n      );\n      expect(updateResults).toBeDefined();\n      expect(updateResults.affected).toBe(1);\n    });\n  });\n\n  describe('deleteSong', () => {\n    it('should delete the song', async () => {\n      const deleteResult = await controller.deleteSong('a uuid');\n      expect(deleteResult.affected).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  Delete,\n  Get,\n  Param,\n  Post,\n  Put,\n} from '@nestjs/common';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\n\n@Controller('songs')\nexport class SongController {\n  constructor(private songService: SongService) {}\n  @Get()\n  getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n  }\n  @Get(':id')\n  getSong(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Post()\n  createSong(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ): Promise<Song> {\n    return this.songService.createSong(createSongDTO);\n  }\n\n  @Put(':id')\n  updateSong(\n    @Param('id')\n    id: string,\n    @Body()\n    updateSongDTO: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, updateSongDTO);\n  }\n\n  @Delete(':id')\n  deleteSong(\n    @Param('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.entity.ts",
    "content": "import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('songs')\nexport class Song {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column()\n  title: string;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.graphql",
    "content": "enum CacheControlScope {\n  PUBLIC\n  PRIVATE\n}\n\ndirective @cacheControl(\n  maxAge: Int\n  scope: CacheControlScope\n  inheritMaxAge: Boolean\n) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION\n\ntype Song @cacheControl(maxAge: 240) {\n  id: ID!\n  title: String @cacheControl(maxAge: 30)\n}\n\ntype Query {\n  songs: [Song!]!\n  song(id: ID!): Song!\n}\n\ntype Mutation {\n  createSong(createSongInput: CreateSongInput!): Song!\n  updateSong(id: ID!, updateSongInput: UpdateSongInput!): UpdateResult!\n  deleteSong(id: ID!): DeleteResult!\n}\n\ntype Subscription {\n  songCreated: Song!\n}\n\ninput CreateSongInput {\n  title: String!\n}\n\ninput UpdateSongInput {\n  title: String\n}\n\ntype UpdateResult {\n  affected: Int!\n}\n\ntype DeleteResult {\n  affected: Int!\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongController } from './song.controller';\nimport { SongService } from './song.service';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from './song.entity';\nimport { SongResolver } from './song.resolver';\n\n@Module({\n  imports: [TypeOrmModule.forFeature([Song])],\n  controllers: [SongController],\n  providers: [SongService, SongResolver],\n})\nexport class SongModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongResolver } from './song.resolver';\nimport { SongService } from '../../src/song/song.service';\nimport { CreateSongInput, UpdateSongInput } from '../../src/graphql';\n\ndescribe('SongResolver', () => {\n  let resolver: SongResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongResolver,\n        {\n          provide: SongService,\n          useValue: {\n            getSongs: jest\n              .fn()\n              .mockResolvedValue([{ id: 'a uuid', title: 'Dancing Feat' }]),\n            getSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ id: id, title: 'Dancing' });\n            }),\n            createSong: jest\n              .fn()\n              .mockImplementation((createSongInput: CreateSongInput) => {\n                return Promise.resolve({ id: 'a uuid', ...createSongInput });\n              }),\n            updateSong: jest\n              .fn()\n              .mockImplementation(\n                (id, string, updateSongInput: UpdateSongInput) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n\n            deleteSong: jest.fn().mockImplementation((id: string) => {\n              return Promise.resolve({ affected: 1 });\n            }),\n          },\n        },\n      ],\n    }).compile();\n\n    resolver = module.get<SongResolver>(SongResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n\n  it('should fetch the songs', async () => {\n    const songs = await resolver.getSongs();\n    expect(songs).toEqual([{ id: 'a uuid', title: 'Dancing Feat' }]);\n    expect(songs.length).toBe(1);\n  });\n\n  it('should create new song', async () => {\n    const song = await resolver.createSong({ title: 'Animals' });\n    expect(song).toEqual({ id: 'a uuid', title: 'Animals' });\n  });\n\n  it('should update the song', async () => {\n    const song = await resolver.updateSong('a uuid', { title: 'DANCING FEAT' });\n    expect(song.affected).toBe(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await resolver.deleteSong('a uuid');\n    expect(song.affected).toBe(1);\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.resolver.ts",
    "content": "import { Args, Mutation, Resolver, Subscription } from '@nestjs/graphql';\nimport { SongService } from './song.service';\nimport { Query } from '@nestjs/graphql';\nimport { CreateSongInput, Song } from '../graphql';\nimport { UpdateSongDTO } from './dto/update-song-dto';\nimport { DeleteResult, UpdateResult } from 'typeorm';\nimport { GraphQLError } from 'graphql';\nimport { PubSub } from 'graphql-subscriptions';\n\nconst pubSub = new PubSub();\n\n@Resolver()\nexport class SongResolver {\n  constructor(private songService: SongService) {}\n\n  @Query('songs')\n  async getSongs(): Promise<Song[]> {\n    return this.songService.getSongs();\n    // throw new Error('Unable to fetch songs!');\n    // throw new GraphQLError('Unable to fetch the songs', {\n    //   extensions: {\n    //     code: 'INTERNAL_SERVER_ERROR',\n    //   },\n    // });\n  }\n\n  @Query('song')\n  async getSong(\n    @Args('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.getSong(id);\n  }\n\n  @Mutation('createSong')\n  async createSong(\n    @Args('createSongInput')\n    args: CreateSongInput,\n  ): Promise<Song> {\n    const newSong = this.songService.createSong(args);\n    pubSub.publish('songCreated', { songCreated: newSong });\n    return newSong;\n  }\n  @Mutation('updateSong')\n  async updateSong(\n    @Args('id')\n    id: string,\n    @Args('updateSongInput')\n    args: UpdateSongDTO,\n  ): Promise<UpdateResult> {\n    return this.songService.updateSong(id, args);\n  }\n\n  @Mutation('deleteSong')\n  async deleteSong(\n    @Args('id')\n    id: string,\n  ): Promise<DeleteResult> {\n    return this.songService.deleteSong(id);\n  }\n\n  @Subscription('songCreated')\n  songCreated() {\n    return pubSub.asyncIterator('songCreated'); //1\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongService } from './song.service';\nimport { Song } from './song.entity';\nimport { FindOneOptions, Repository } from 'typeorm';\nimport { getRepositoryToken } from '@nestjs/typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\ndescribe('SongService', () => {\n  let service: SongService;\n  let repo: Repository<Song>;\n\n  const oneSong = { id: 'a uuid', title: 'Lover' };\n  const songArray = [{ id: 'a uuid', title: 'Lover' }];\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [\n        SongService,\n        {\n          provide: getRepositoryToken(Song),\n          useValue: {\n            find: jest\n              .fn()\n              .mockImplementation(() => Promise.resolve(songArray)),\n            findOneOrFail: jest\n              .fn()\n              .mockImplementation((options: FindOneOptions<Song>) => {\n                return Promise.resolve(oneSong);\n              }),\n            create: jest\n              .fn()\n              .mockImplementation((createSongDTO: CreateSongDTO) => {\n                return Promise.resolve(oneSong);\n              }),\n            save: jest.fn(),\n            update: jest\n              .fn()\n              .mockImplementation(\n                (id: string, updateSongDTO: UpdateSongDTO) => {\n                  return Promise.resolve({ affected: 1 });\n                },\n              ),\n            delete: jest\n              .fn()\n              .mockImplementation((id: string) =>\n                Promise.resolve({ affected: 1 }),\n              ),\n          },\n        },\n      ],\n    }).compile();\n\n    service = module.get<SongService>(SongService);\n    repo = module.get<Repository<Song>>(getRepositoryToken(Song));\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n\n  it('should give me the song by id', async () => {\n    const song = await service.getSong('a uuid');\n    const repoSpy = jest.spyOn(repo, 'findOneOrFail');\n    expect(song).toEqual(oneSong);\n    expect(repoSpy).toBeCalledWith({ where: { id: 'a uuid' } });\n  });\n\n  it('should create the song', async () => {\n    const song = await service.createSong({ title: 'Lover' });\n    expect(song).toEqual(oneSong);\n    expect(repo.create).toBeCalledTimes(1);\n    expect(repo.create).toBeCalledWith({ title: 'Lover' });\n  });\n\n  it('should update the song', async () => {\n    const result = await service.updateSong('a uuid', { title: 'Lover' });\n    expect(repo.update).toBeCalledTimes(1);\n    expect(result.affected).toEqual(1);\n  });\n\n  it('should delete the song', async () => {\n    const song = await service.deleteSong('a uuid');\n    const repoSpyOn = jest.spyOn(repo, 'delete');\n    expect(repo.delete).toBeCalledTimes(1);\n    expect(song.affected).toBe(1);\n    expect(repoSpyOn).toBeCalledWith('a uuid');\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/src/song/song.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Song } from './song.entity';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { DeleteResult, Repository, UpdateResult } from 'typeorm';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { UpdateSongDTO } from './dto/update-song-dto';\n\n@Injectable()\nexport class SongService {\n  constructor(\n    @InjectRepository(Song)\n    private readonly songRepo: Repository<Song>,\n  ) {}\n  async getSongs(): Promise<Song[]> {\n    return this.songRepo.find();\n  }\n  getSong(id: string) {\n    return this.songRepo.findOneOrFail({ where: { id } });\n  }\n  async createSong(createSongDTO: CreateSongDTO) {\n    const newSong = this.songRepo.create(createSongDTO);\n    await this.songRepo.save(newSong);\n    return newSong;\n  }\n  async updateSong(id, updateSongDTO: UpdateSongDTO): Promise<UpdateResult> {\n    return this.songRepo.update({ id }, updateSongDTO);\n  }\n  async deleteSong(id: string): Promise<DeleteResult> {\n    return this.songRepo.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/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": "module-19-graphql-advanced-concepts/lesson-01/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\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"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"printWidth\": 100\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo_text.svg\" width=\"320\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/nest-cli.json",
    "content": "{\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/package.json",
    "content": "{\n  \"name\": \"example-app\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^7.6.15\",\n    \"@nestjs/core\": \"^7.6.15\",\n    \"@nestjs/graphql\": \"^7.11.0\",\n    \"@nestjs/platform-express\": \"^7.6.15\",\n    \"apollo-server-express\": \"^2.25.2\",\n    \"dataloader\": \"^2.0.0\",\n    \"graphql\": \"^15.5.1\",\n    \"graphql-tools\": \"^7.0.5\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rimraf\": \"^3.0.2\",\n    \"rxjs\": \"^6.6.6\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^7.6.0\",\n    \"@nestjs/schematics\": \"^7.3.0\",\n    \"@nestjs/testing\": \"^7.6.15\",\n    \"@types/express\": \"^4.17.11\",\n    \"@types/jest\": \"^26.0.22\",\n    \"@types/node\": \"^14.14.36\",\n    \"@types/supertest\": \"^2.0.10\",\n    \"@typescript-eslint/eslint-plugin\": \"^4.19.0\",\n    \"@typescript-eslint/parser\": \"^4.19.0\",\n    \"eslint\": \"^7.22.0\",\n    \"eslint-config-prettier\": \"^8.1.0\",\n    \"eslint-plugin-prettier\": \"^3.3.1\",\n    \"jest\": \"^26.6.3\",\n    \"prettier\": \"^2.2.1\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"^26.5.4\",\n    \"ts-loader\": \"^8.0.18\",\n    \"ts-node\": \"^9.1.1\",\n    \"tsconfig-paths\": \"^3.9.0\",\n    \"typescript\": \"^4.2.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { join } from 'path';\n\nimport { PostsModule } from './posts/posts.module';\nimport { createUsersLoader } from './users/users.loader';\nimport { UsersModule } from './users/users.module';\nimport { UsersService } from './users/users.service';\n\n@Module({\n  imports: [\n    PostsModule,\n    GraphQLModule.forRootAsync({\n      imports: [UsersModule],\n      useFactory: (usersService: UsersService) => ({\n        autoSchemaFile: join(process.cwd(), 'src/schema.gql'),\n        context: () => ({\n          randomValue: Math.random(),\n          usersLoader: createUsersLoader(usersService),\n        }),\n      }),\n      inject: [UsersService],\n    }),\n  ],\n  controllers: [],\n  providers: [],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/posts/post.entity.ts",
    "content": "import { Field, ObjectType } from '@nestjs/graphql';\n\nimport { User } from '../users/user.entity';\n\n@ObjectType()\nexport class Post {\n  @Field()\n  id: string;\n\n  @Field()\n  title: string;\n\n  @Field()\n  body: string;\n\n  userId: number;\n\n  @Field(() => User)\n  createdBy?: User;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/posts/posts.module.ts",
    "content": "import { Module } from '@nestjs/common';\n\nimport { PostsResolver } from './posts.resolver';\nimport { PostsService } from './posts.service';\nimport { UsersService } from 'src/users/users.service';\nimport { UsersModule } from 'src/users/users.module';\n\n@Module({\n  imports: [UsersModule],\n  providers: [PostsService, PostsResolver, UsersService],\n})\nexport class PostsModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/posts/posts.resolver.ts",
    "content": "import { Context, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql';\nimport * as DataLoader from 'dataloader';\n\nimport { User } from '../users/user.entity';\nimport { Post } from './post.entity';\nimport { PostsService } from './posts.service';\nimport { UsersService } from 'src/users/users.service';\n\n@Resolver(Post)\nexport class PostsResolver {\n  constructor(private readonly postsService: PostsService, private userService: UsersService) {}\n\n  @Query(() => [Post], { name: 'posts' })\n  getPosts() {\n    return this.postsService.getPosts();\n  }\n\n  @ResolveField('createdBy', () => User)\n  getCreatedBy(\n    @Parent() post: Post,\n    @Context('usersLoader') usersLoader: DataLoader<number, User>,\n  ) {\n    const { userId } = post;\n    return usersLoader.load(userId);\n    // return this.userService.getUser(userId);\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/posts/posts.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\nimport { delay } from '../util';\nimport { Post } from './post.entity';\n\n@Injectable()\nexport class PostsService {\n  private posts: Post[] = [\n    { id: 'post-1', title: 'Post 1', body: 'Lorem 1', userId: 1 },\n    { id: 'post-2', title: 'Post 2', body: 'Lorem 2', userId: 1 },\n    { id: 'post-3', title: 'Post 3', body: 'Lorem 3', userId: 2 },\n    { id: 'post-4', title: 'Post 4', body: 'Somehting', userId: 4 },\n  ];\n\n  async getPosts() {\n    console.log('Getting posts...');\n    await delay(3000);\n    return this.posts;\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/schema.gql",
    "content": "# ------------------------------------------------------\n# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n# ------------------------------------------------------\n\ntype User {\n  id: Int!\n  name: String!\n}\n\ntype Post {\n  id: String!\n  title: String!\n  body: String!\n  createdBy: User!\n}\n\ntype Query {\n  posts: [Post!]!\n  users: [User!]!\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/users/user.entity.ts",
    "content": "import { Field, Int, ObjectType } from '@nestjs/graphql';\n\n@ObjectType()\nexport class User {\n  @Field(() => Int)\n  id: number;\n\n  @Field()\n  name: string;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/users/users.loader.ts",
    "content": "import * as DataLoader from 'dataloader';\n\nimport { mapFromArray } from '../util';\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\nexport function createUsersLoader(usersService: UsersService) {\n  return new DataLoader<number, User>(async (ids) => {\n    const users = await usersService.getUsersByIds(ids);\n\n    const usersMap = mapFromArray(users, (user) => user.id);\n\n    console.log('usersMap', usersMap);\n    const results = ids.map((id) => usersMap[id]);\n    console.log('results', results);\n    return results;\n  });\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\n\nimport { UsersResolver } from './users.resolver';\nimport { UsersService } from './users.service';\n\n@Module({\n  providers: [UsersService, UsersResolver],\n  exports: [UsersService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/users/users.resolver.ts",
    "content": "import { Query, Resolver } from '@nestjs/graphql';\n\nimport { User } from './user.entity';\nimport { UsersService } from './users.service';\n\n@Resolver(User)\nexport class UsersResolver {\n  constructor(private readonly usersService: UsersService) {}\n\n  @Query(() => [User], { name: 'users' })\n  getUsers() {\n    return this.usersService.getUsers();\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/users/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\nimport { delay } from '../util';\nimport { User } from './user.entity';\n\n@Injectable()\nexport class UsersService {\n  private users: User[] = [\n    { id: 1, name: 'John' },\n    { id: 2, name: 'Jane' },\n    { id: 3, name: 'Alex' },\n    { id: 4, name: 'Anna' },\n  ];\n\n  async getUsers() {\n    console.log('Getting users...');\n    await delay(3000);\n    return this.users;\n  }\n\n  async getUser(id: number) {\n    console.log(`FETCHING DATA FROM DB: Getting user with id ${id}...`);\n    await delay(1000);\n    return this.users.find((user) => user.id === id);\n  }\n\n  async getUsersByIds(ids: readonly number[]) {\n    console.log(`Getting users with ids (${ids.join(',')})`);\n    await delay(1000);\n    return this.users.filter((u) => ids.includes(u.id));\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/src/util.ts",
    "content": "export function delay(timeout: number) {\n  return new Promise<void>((resolve) => setTimeout(() => resolve(), timeout));\n}\n\nexport function mapFromArray<T>(\n  array: T[],\n  keyStrategy: (v: T) => string | number,\n) {\n  const map: Record<string | number, T | undefined> = {};\n\n  for (const item of array) {\n    map[keyStrategy(item)] = item;\n  }\n\n  return map;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/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": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-02-dataloaders/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/api.http",
    "content": "### Create Song Endpoint\nPOST http://localhost:3001/songs\nContent-Type: application/json\n\n{\n     \"title\": \"Danza \",\n    \"releasedDate\" : \"2023-05-11\",\n    \"duration\" :\"02:33\",\n    \"lyrics\": \"1adas adsdasd asdasdasd qeqew\",\n    \"album\": \"648097fd6535d2cff889633d\"\n}\n\n\n### Find Songs\nGET http://localhost:3001/songs\n\n### Delete Song\nDELETE http://localhost:3001/songs/648047e39cd98439a21a741e\n\n\n### Create PlayList\nPOST http://localhost:3001/albums\nContent-Type: application/json\n\n{\n    \"title\": \"Dance Music\",\n    \"songs\": [\"648097fd6535d2cff889633d\"]\n}\n\n### Find Albums\nGET http://localhost:3001/albums"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/docker-compose.yml",
    "content": "version: '3'\n\nservices:\n  mongodb: \n    image: mongo:latest \n    environment:\n      - MONGODB_DATABASE=\"test\"\n    ports:\n      - 27017:27017"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/generate-typings.ts",
    "content": "import { GraphQLDefinitionsFactory } from '@nestjs/graphql';\nimport { join } from 'path';\n\nconst definitionsFactory = new GraphQLDefinitionsFactory();\ndefinitionsFactory.generate({\n  typePaths: ['./src/**/*.graphql'],\n  path: join(process.cwd(), 'src/graphql.ts'),\n  outputAs: 'class',\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/package.json",
    "content": "{\n  \"name\": \"n-mongo-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@apollo/datasource-rest\": \"^6.0.1\",\n    \"@apollo/server\": \"^4.8.0\",\n    \"@nestjs/apollo\": \"^12.0.7\",\n    \"@nestjs/common\": \"^9.0.0\",\n    \"@nestjs/core\": \"^9.0.0\",\n    \"@nestjs/graphql\": \"^12.0.8\",\n    \"@nestjs/mongoose\": \"^9.2.2\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"graphql\": \"^16.7.1\",\n    \"mongoose\": \"^7.2.2\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.2.0\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.0.0\",\n    \"@nestjs/schematics\": \"^9.0.0\",\n    \"@nestjs/testing\": \"^9.0.0\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"18.11.18\",\n    \"@types/supertest\": \"^2.0.11\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.0.0\",\n    \"@typescript-eslint/parser\": \"^5.0.0\",\n    \"eslint\": \"^8.0.1\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.3.2\",\n    \"source-map-support\": \"^0.5.20\",\n    \"supertest\": \"^6.1.3\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.2.3\",\n    \"ts-node\": \"^10.0.0\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\",\n    \"webpack\": \"^5.88.2\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/album/album.controller.ts",
    "content": "import { Body, Controller, Get, Post } from '@nestjs/common';\nimport { Album } from './schemas/album.schema';\nimport { AlbumService } from './album.service';\nimport { CreateAlbumDTO } from './dto/create-album-dto';\n\n@Controller('albums')\nexport class AlbumController {\n  constructor(private albumService: AlbumService) {}\n  @Post()\n  create(\n    @Body()\n    createAlbumDTO: CreateAlbumDTO,\n  ): Promise<Album> {\n    return this.albumService.createAlbum(createAlbumDTO);\n  }\n\n  @Get()\n  find(): Promise<Album[]> {\n    return this.albumService.findAlbums();\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/album/album.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AlbumController } from './album.controller';\nimport { AlbumService } from './album.service';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { Album, AlbumSchema } from './schemas/album.schema';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Album.name, schema: AlbumSchema }]),\n  ],\n  controllers: [AlbumController],\n  providers: [AlbumService],\n})\nexport class AlbumModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/album/album.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Album, AlbumDocument } from './schemas/album.schema';\nimport { Model } from 'mongoose';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { CreateAlbumDTO } from './dto/create-album-dto';\nimport { Song } from 'src/songs/schemas/song.schema';\n\n@Injectable()\nexport class AlbumService {\n  constructor(\n    @InjectModel(Album.name)\n    private readonly albumModel: Model<AlbumDocument>,\n  ) {}\n  async createAlbum(createAlbumDTO: CreateAlbumDTO): Promise<Album> {\n    return this.albumModel.create(createAlbumDTO);\n  }\n\n  async findAlbums() {\n    return this.albumModel.find().populate('songs', null, Song.name);\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/album/dto/create-album-dto.ts",
    "content": "export class CreateAlbumDTO {\n  title: string;\n  songs: string[];\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/album/schemas/album.schema.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument, Schema as MongooseSchema, Types } from 'mongoose';\nimport { Song } from 'src/songs/schemas/song.schema';\n\nexport type AlbumDocument = HydratedDocument<Album>;\n\n@Schema()\nexport class Album {\n  @Prop({\n    required: true,\n  })\n  title: string;\n\n  @Prop({ type: [Types.ObjectId], ref: 'songs' })\n  songs: Song[];\n}\n\nexport const AlbumSchema = SchemaFactory.createForClass(Album);\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/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": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { SongsModule } from './songs/songs.module';\nimport { AlbumModule } from './album/album.module';\nimport { ProductModule } from './product/product.module';\nimport { UserModule } from './user/user.module';\n\nimport { join } from 'path';\nimport { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';\nimport { GraphQLModule } from '@nestjs/graphql';\nimport { TodoModule } from './todo/todo.module';\nimport * as mongoose from 'mongoose';\nimport { TodoService } from './todo/todo.service';\n\nmongoose.set('debug', true);\n\nconst dataSources = () => ({\n  todoAPI: new TodoService(),\n});\n\n@Module({\n  imports: [\n    GraphQLModule.forRoot<ApolloDriverConfig>({\n      driver: ApolloDriver,\n      typePaths: ['./**/*.graphql'],\n      definitions: {\n        path: join(process.cwd(), 'src/graphql.ts'),\n        outputAs: 'class',\n      },\n      context: async () => ({\n        dataSources,\n      }),\n    }),\n    MongooseModule.forRoot('mongodb://localhost:27017/test'),\n    SongsModule,\n    AlbumModule,\n    ProductModule,\n    UserModule,\n    TodoModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/graphql.ts",
    "content": "\n/*\n * -------------------------------------------------------\n * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)\n * -------------------------------------------------------\n */\n\n/* tslint:disable */\n/* eslint-disable */\n\nexport enum Status {\n    NEW = \"NEW\",\n    RELEASED = \"RELEASED\",\n    FAILED = \"FAILED\"\n}\n\nexport class ProductInput {\n    name: string;\n    qty?: Nullable<number>;\n    status?: Nullable<Status>;\n}\n\nexport class Owner {\n    _id: string;\n    name: string;\n}\n\nexport class Product {\n    _id?: Nullable<string>;\n    name: string;\n    qty?: Nullable<number>;\n    owner: Owner;\n    status?: Nullable<Status>;\n}\n\nexport abstract class IQuery {\n    abstract product(_id?: Nullable<string>): Product | Promise<Product>;\n\n    abstract products(): Nullable<Product>[] | Promise<Nullable<Product>[]>;\n\n    abstract todos(): Todo[] | Promise<Todo[]>;\n}\n\nexport abstract class IMutation {\n    abstract createProduct(input: ProductInput): Product | Promise<Product>;\n\n    abstract updateProduct(_id: string, input: ProductInput): Product | Promise<Product>;\n\n    abstract deleteProduct(_id: string): Product | Promise<Product>;\n}\n\nexport class Todo {\n    id: string;\n    userId: number;\n    title: string;\n    completed?: Nullable<boolean>;\n}\n\ntype Nullable<T> = T | null;\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product-owner.resolver.ts",
    "content": "import { Resolver, Query, ResolveField, Parent } from '@nestjs/graphql';\nimport { ProductService } from './product.service';\nimport { UserService } from '../user/user.service';\nimport { Product } from 'src/graphql';\n\n@Resolver('Product')\nexport class ProductOwnerResolver {\n  constructor(\n    private productService: ProductService,\n    private ownerService: UserService,\n  ) {}\n\n  @ResolveField('owner')\n  async getOwner(\n    @Parent()\n    product: Product,\n  ) {\n    console.log('DB CALLED');\n    return await this.ownerService.findOneById(product.owner);\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product.graphql",
    "content": "enum Status {\n  NEW\n  RELEASED\n  FAILED\n}\ntype Owner {\n  _id: ID!\n  name: String!\n}\n\ntype Product {\n  _id: ID\n  name: String!\n  qty: Int\n  owner: Owner!\n  status: Status\n}\n\ntype Query {\n  product(_id: ID): Product!\n  products: [Product]!\n}\ninput ProductInput {\n  name: String!\n  qty: Int\n  status: Status\n}\n\ntype Mutation {\n  createProduct(input: ProductInput!): Product!\n  updateProduct(_id: ID!, input: ProductInput!): Product!\n  deleteProduct(_id: ID!): Product!\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { Product, ProductSchema } from './schemas/product.schema';\nimport { ProductResolver } from './product.resolver';\nimport { ProductService } from './product.service';\nimport { ProductOwnerResolver } from './product-owner.resolver';\nimport { UserModule } from 'src/user/user.module';\nimport { UserService } from 'src/user/user.service';\nimport { User, UserSchema } from 'src/user/schemas/user.schema';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([\n      { name: Product.name, schema: ProductSchema },\n      { name: User.name, schema: UserSchema },\n    ]),\n    UserModule,\n  ],\n  providers: [\n    ProductResolver,\n    ProductService,\n    ProductOwnerResolver,\n    UserService,\n  ],\n})\nexport class ProductModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ProductResolver } from './product.resolver';\n\ndescribe('ProductResolver', () => {\n  let resolver: ProductResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ProductResolver],\n    }).compile();\n\n    resolver = module.get<ProductResolver>(ProductResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product.resolver.ts",
    "content": "import { Resolver, Query } from '@nestjs/graphql';\nimport { Product } from './schemas/product.schema';\nimport { ProductService } from './product.service';\n\n@Resolver()\nexport class ProductResolver {\n  constructor(private productService: ProductService) {}\n\n  @Query('products')\n  async getProducts(): Promise<Product[]> {\n    return this.productService.fetchProducts();\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ProductService } from './product.service';\n\ndescribe('ProductService', () => {\n  let service: ProductService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ProductService],\n    }).compile();\n\n    service = module.get<ProductService>(ProductService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/product.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { Model } from 'mongoose';\n\nimport { Product, ProductDocument } from './schemas/product.schema';\n\n@Injectable()\nexport class ProductService {\n  constructor(\n    @InjectModel(Product.name)\n    private readonly productModel: Model<ProductDocument>,\n  ) {}\n\n  async fetchProducts(): Promise<Product[]> {\n    const results = await this.productModel.find();\n    console.log(results);\n    return results;\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/product/schemas/product.schema.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument, Schema as MongooseSchema, Types } from 'mongoose';\nimport { User } from 'src/user/schemas/user.schema';\n\nexport type ProductDocument = HydratedDocument<Product>;\n\n@Schema()\nexport class Product {\n  @Prop({\n    required: true,\n  })\n  name: string;\n\n  @Prop({\n    type: Number,\n  })\n  qty: number;\n\n  @Prop({\n    type: String,\n    enum: ['NEW', 'RELEASED', 'FAILED'],\n    default: 'NEW',\n  })\n  status: string;\n\n  @Prop({\n    type: Types.ObjectId,\n    ref: User.name,\n  })\n  owner: User;\n}\n\nexport const ProductSchema = SchemaFactory.createForClass(Product);\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/dto/create-song-dto.ts",
    "content": "export class CreateSongDTO {\n  title: string;\n  releasedDate: Date;\n  duration: Date;\n  lyrics: string;\n  album: string;\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/schemas/song.schema.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument, Types } from 'mongoose';\nimport { Album } from 'src/album/schemas/album.schema';\n\nexport type SongDocument = HydratedDocument<Song>;\n\n@Schema()\nexport class Song {\n  @Prop({\n    required: true,\n  })\n  title: string;\n\n  @Prop({\n    required: true,\n  })\n  releasedDate: Date;\n\n  @Prop({\n    required: true,\n  })\n  duration: string;\n\n  lyrics: string;\n\n  @Prop({\n    type: Types.ObjectId,\n    ref: Album.name,\n  })\n  album: Album;\n}\n\nexport const SongSchema = SchemaFactory.createForClass(Song);\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/songs.controller.ts",
    "content": "import { Body, Controller, Post, Get, Param, Delete } from '@nestjs/common';\nimport { CreateSongDTO } from './dto/create-song-dto';\nimport { SongsService } from './songs.service';\nimport { Song } from './schemas/song.schema';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private songService: SongsService) {}\n  @Post()\n  create(\n    @Body()\n    createSongDTO: CreateSongDTO,\n  ) {\n    return this.songService.create(createSongDTO);\n  }\n\n  @Get()\n  find(): Promise<Song[]> {\n    return this.songService.find();\n  }\n  @Get(':id')\n  findOne(\n    @Param('id')\n    id: string,\n  ): Promise<Song> {\n    return this.songService.findById(id);\n  }\n  @Delete(':id')\n  delete(\n    @Param('id')\n    id: string,\n  ) {\n    return this.songService.delete(id);\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { Song, SongSchema } from './schemas/song.schema';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: Song.name, schema: SongSchema }]),\n  ],\n  controllers: [SongsController],\n  providers: [SongsService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport { Song, SongDocument } from './schemas/song.schema';\nimport { Model } from 'mongoose';\nimport { CreateSongDTO } from './dto/create-song-dto';\n\n@Injectable()\nexport class SongsService {\n  constructor(\n    @InjectModel(Song.name)\n    private readonly songModel: Model<SongDocument>,\n  ) {}\n\n  async create(createSongDTO: CreateSongDTO): Promise<Song> {\n    const song = await this.songModel.create(createSongDTO);\n    return song;\n  }\n  async find(): Promise<Song[]> {\n    return this.songModel.find();\n  }\n\n  async findById(id: string): Promise<Song> {\n    return this.songModel.findById(id);\n  }\n\n  async delete(id: string) {\n    return this.songModel.deleteOne({ _id: id });\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/todo/todo.graphql",
    "content": "type Todo {\n  id: ID!\n  userId: Int!\n  title: String!\n  completed: Boolean\n}\n\ntype Query {\n  todos: [Todo!]!\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/todo/todo.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { TodoService } from './todo.service';\nimport { TodoResolver } from './todo.resolver';\n\n@Module({\n  providers: [TodoService, TodoResolver]\n})\nexport class TodoModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/todo/todo.resolver.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TodoResolver } from './todo.resolver';\n\ndescribe('TodoResolver', () => {\n  let resolver: TodoResolver;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TodoResolver],\n    }).compile();\n\n    resolver = module.get<TodoResolver>(TodoResolver);\n  });\n\n  it('should be defined', () => {\n    expect(resolver).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/todo/todo.resolver.ts",
    "content": "import { Context, Resolver } from '@nestjs/graphql';\nimport { Query } from '@nestjs/graphql';\n\n@Resolver()\nexport class TodoResolver {\n  @Query('todos')\n  async getTodods(\n    @Context('dataSources')\n    dataSources,\n  ) {\n    return dataSources().todoAPI.getTodos();\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/todo/todo.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TodoService } from './todo.service';\n\ndescribe('TodoService', () => {\n  let service: TodoService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TodoService],\n    }).compile();\n\n    service = module.get<TodoService>(TodoService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/todo/todo.service.ts",
    "content": "import { RESTDataSource } from '@apollo/datasource-rest';\nimport { Injectable } from '@nestjs/common';\nimport { Todo } from 'src/graphql';\n\n@Injectable()\nexport class TodoService extends RESTDataSource {\n  constructor() {\n    super();\n    this.baseURL = 'https://jsonplaceholder.typicode.com';\n  }\n  async getTodos(): Promise<Todo[]> {\n    return this.get('/todos');\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/user/schemas/user.schema.ts",
    "content": "import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';\nimport { HydratedDocument, Schema as MongooseSchema, Types } from 'mongoose';\nimport { Product } from 'src/product/schemas/product.schema';\n\nexport type UserDocument = HydratedDocument<User>;\n\n@Schema()\nexport class User {\n  @Prop({\n    required: true,\n  })\n  name: string;\n\n  @Prop({ type: [Types.ObjectId], ref: 'products' })\n  products: Product[];\n}\n\nexport const UserSchema = SchemaFactory.createForClass(User);\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/user/user.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { MongooseModule } from '@nestjs/mongoose';\nimport { User, UserSchema } from './schemas/user.schema';\nimport { UserService } from './user.service';\n\n@Module({\n  imports: [\n    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),\n  ],\n  providers: [UserService],\n  exports: [UserService],\n})\nexport class UserModule {}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/src/user/user.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { InjectModel } from '@nestjs/mongoose';\nimport mongoose, { Model } from 'mongoose';\nimport { User, UserDocument } from 'src/user/schemas/user.schema';\n\n@Injectable()\nexport class UserService {\n  constructor(\n    @InjectModel(User.name)\n    private readonly userModel: Model<UserDocument>,\n  ) {}\n  async findOneById(ownerId: any) {\n    return await this.userModel.findOne({ _id: ownerId });\n  }\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/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": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-19-graphql-advanced-concepts/lesson-03-fetching-external-api/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/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": "module-20-prisma-integration/lesson-01/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/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": "module-20-prisma-integration/lesson-01/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-01/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-02/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id    Int    @id @default(autoincrement())\n  title String\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/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": "module-20-prisma-integration/lesson-02/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/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": "module-20-prisma-integration/lesson-02/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-02/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-03/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id    Int    @id @default(autoincrement())\n  title String\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/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": "module-20-prisma-integration/lesson-03/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/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": "module-20-prisma-integration/lesson-03/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-03/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/http-client.http",
    "content": "### Create Song\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVER ON THE SUN\"\n}\n\n### FETCH ALL SONGS\n\nGET http://localhost:3000/songs\n\n\n### FETCH SONG BY ID\nGET http://localhost:3000/songs/2\n\n\n### UPDATE SONG BY ID\nPATCH http://localhost:3000/songs/3\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVING ME\"\n}\n\n\n### DELETE Song by id\nDELETE http://localhost:3000/songs/3"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id    Int    @id @default(autoincrement())\n  title String\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/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": "module-20-prisma-integration/lesson-04-and-05/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\n\n@Module({\n  imports: [SongsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/dto/create-song.dto.ts",
    "content": "export class CreateSongDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/dto/update-song.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateSongDto } from './create-song.dto';\n\nexport class UpdateSongDto extends PartialType(CreateSongDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/entities/song.entity.ts",
    "content": "export class Song {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n      providers: [SongsService],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private readonly songsService: SongsService) {}\n\n  @Post()\n  create(@Body() createSongDto: Prisma.SongCreateInput) {\n    return this.songsService.create(createSongDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.songsService.findOne({ id: +id });\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.songsService.update({ id: +id }, updateSongDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.songsService.remove({ id: +id });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { SongsController } from './songs.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService, PrismaService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class SongsService {\n  constructor(private prisma: PrismaService) {}\n  create(createSongDto: Prisma.SongCreateInput) {\n    return this.prisma.song.create({\n      data: createSongDto,\n    });\n  }\n\n  findAll() {\n    return this.prisma.song.findMany();\n  }\n\n  findOne(songWhereUniqueInput: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.findUnique({ where: songWhereUniqueInput });\n  }\n\n  update(\n    where: Prisma.SongWhereUniqueInput,\n    updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.prisma.song.update({\n      where,\n      data: updateSongDto,\n    });\n  }\n\n  remove(where: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.delete({ where });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/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": "module-20-prisma-integration/lesson-04-and-05/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-04-and-05/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/http-client.http",
    "content": "### Create Song\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n    \"title\" : \"Animals\",\n    \"artistId\":1\n}\n\n### FETCH ALL SONGS\n\nGET http://localhost:3000/songs\n\n\n### FETCH SONG BY ID\nGET http://localhost:3000/songs/2\n\n\n### UPDATE SONG BY ID\nPATCH http://localhost:3000/songs/3\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVING ME\"\n}\n\n\n### DELETE Song by id\nDELETE http://localhost:3000/songs/3\n\n### Create Artist\nPOST http://localhost:3000/artists\nContent-Type: application/json\n\n{\n    \"name\" : \"Avicci\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/prisma/migrations/20230801082432_add_artists/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Song\" ADD COLUMN     \"artistId\" INTEGER;\n\n-- CreateTable\nCREATE TABLE \"Artist\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Artist_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- AddForeignKey\nALTER TABLE \"Song\" ADD CONSTRAINT \"Song_artistId_fkey\" FOREIGN KEY (\"artistId\") REFERENCES \"Artist\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-06/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id       Int     @id @default(autoincrement())\n  title    String\n  artist   Artist? @relation(fields: [artistId], references: [id])\n  artistId Int?\n}\n\nmodel Artist {\n  id    Int    @id @default(autoincrement())\n  name  String\n  songs Song[]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/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": "module-20-prisma-integration/lesson-06/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { ArtistsModule } from './artists/artists.module';\n\n@Module({\n  imports: [SongsModule, ArtistsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n      providers: [ArtistsService],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/artists.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('artists')\nexport class ArtistsController {\n  constructor(private readonly artistsService: ArtistsService) {}\n\n  @Post()\n  create(@Body() createArtistDto: Prisma.ArtistCreateInput) {\n    return this.artistsService.create(createArtistDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.artistsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.artistsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateArtistDto: UpdateArtistDto) {\n    return this.artistsService.update(+id, updateArtistDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.artistsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ArtistsController],\n  providers: [ArtistsService, PrismaService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateArtistDto } from './dto/create-artist.dto';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(private prisma: PrismaService) {}\n  create(createArtistDto: Prisma.ArtistCreateInput) {\n    return this.prisma.artist.create({\n      data: createArtistDto,\n    });\n  }\n\n  findAll() {\n    return `This action returns all artists`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} artist`;\n  }\n\n  update(id: number, updateArtistDto: UpdateArtistDto) {\n    return `This action updates a #${id} artist`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} artist`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/dto/create-artist.dto.ts",
    "content": "export class CreateArtistDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/artists/dto/update-artist.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateArtistDto } from './create-artist.dto';\n\nexport class UpdateArtistDto extends PartialType(CreateArtistDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/dto/create-song.dto.ts",
    "content": "export class CreateSongDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/dto/update-song.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateSongDto } from './create-song.dto';\n\nexport class UpdateSongDto extends PartialType(CreateSongDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n      providers: [SongsService],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private readonly songsService: SongsService) {}\n\n  @Post()\n  create(@Body() createSongDto: Prisma.SongCreateInput) {\n    return this.songsService.create(createSongDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.songsService.findOne({ id: +id });\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.songsService.update({ id: +id }, updateSongDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.songsService.remove({ id: +id });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { SongsController } from './songs.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService, PrismaService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class SongsService {\n  constructor(private prisma: PrismaService) {}\n  create(createSongDto: Prisma.SongUncheckedCreateInput) {\n    return this.prisma.song.create({\n      data: createSongDto,\n    });\n  }\n\n  findAll() {\n    return this.prisma.song.findMany({ include: { artist: true } });\n  }\n\n  findOne(songWhereUniqueInput: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.findUnique({ where: songWhereUniqueInput });\n  }\n\n  update(\n    where: Prisma.SongWhereUniqueInput,\n    updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.prisma.song.update({\n      where,\n      data: updateSongDto,\n    });\n  }\n\n  remove(where: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.delete({ where });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/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": "module-20-prisma-integration/lesson-06/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-06/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/http-client.http",
    "content": "### Create Song\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n    \"title\" : \"Animals\",\n    \"artistId\":1\n}\n\n### FETCH ALL SONGS\n\nGET http://localhost:3000/songs\n\n\n### FETCH SONG BY ID\nGET http://localhost:3000/songs/2\n\n\n### UPDATE SONG BY ID\nPATCH http://localhost:3000/songs/3\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVING ME\"\n}\n\n\n### DELETE Song by id\nDELETE http://localhost:3000/songs/3\n\n### Create Artist\nPOST http://localhost:3000/artists\nContent-Type: application/json\n\n{\n    \"name\" : \"Avicci\"\n}\n\n### Create User\nPOST http://localhost:3000/users\nContent-Type: application/json\n\n{\n    \"name\" : \"Jane Doe\",\n    \"photo\": \"some-api.com/photos/1.jpg\",\n    \"phone\": \"+9234344433\"\n}\n\n### FETCH Users\nGET http://localhost:3000/users"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/prisma/migrations/20230801082432_add_artists/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Song\" ADD COLUMN     \"artistId\" INTEGER;\n\n-- CreateTable\nCREATE TABLE \"Artist\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Artist_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- AddForeignKey\nALTER TABLE \"Song\" ADD CONSTRAINT \"Song_artistId_fkey\" FOREIGN KEY (\"artistId\") REFERENCES \"Artist\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/prisma/migrations/20230801091013_one_to_one/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"User\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"User_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Profile\" (\n    \"id\" SERIAL NOT NULL,\n    \"userId\" INTEGER NOT NULL,\n    \"photo\" TEXT NOT NULL,\n    \"phone\" TEXT NOT NULL,\n\n    CONSTRAINT \"Profile_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Profile_userId_key\" ON \"Profile\"(\"userId\");\n\n-- AddForeignKey\nALTER TABLE \"Profile\" ADD CONSTRAINT \"Profile_userId_fkey\" FOREIGN KEY (\"userId\") REFERENCES \"User\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-07/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id       Int     @id @default(autoincrement())\n  title    String\n  artist   Artist? @relation(fields: [artistId], references: [id])\n  artistId Int?\n}\n\nmodel Artist {\n  id    Int    @id @default(autoincrement())\n  name  String\n  songs Song[]\n}\n\nmodel User {\n  id   Int    @id @default(autoincrement())\n  name String\n\n  profile Profile?\n}\n\nmodel Profile {\n  id     Int    @id @default(autoincrement())\n  user   User   @relation(fields: [userId], references: [id])\n  userId Int    @unique\n  photo  String\n  phone  String\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/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": "module-20-prisma-integration/lesson-07/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { UsersModule } from './users/users.module';\n\n@Module({\n  imports: [SongsModule, ArtistsModule, UsersModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n      providers: [ArtistsService],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/artists.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('artists')\nexport class ArtistsController {\n  constructor(private readonly artistsService: ArtistsService) {}\n\n  @Post()\n  create(@Body() createArtistDto: Prisma.ArtistCreateInput) {\n    return this.artistsService.create(createArtistDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.artistsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.artistsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateArtistDto: UpdateArtistDto) {\n    return this.artistsService.update(+id, updateArtistDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.artistsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ArtistsController],\n  providers: [ArtistsService, PrismaService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateArtistDto } from './dto/create-artist.dto';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(private prisma: PrismaService) {}\n  create(createArtistDto: Prisma.ArtistCreateInput) {\n    return this.prisma.artist.create({\n      data: createArtistDto,\n    });\n  }\n\n  findAll() {\n    return `This action returns all artists`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} artist`;\n  }\n\n  update(id: number, updateArtistDto: UpdateArtistDto) {\n    return `This action updates a #${id} artist`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} artist`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/dto/create-artist.dto.ts",
    "content": "export class CreateArtistDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/artists/dto/update-artist.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateArtistDto } from './create-artist.dto';\n\nexport class UpdateArtistDto extends PartialType(CreateArtistDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/dto/create-song.dto.ts",
    "content": "export class CreateSongDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/dto/update-song.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateSongDto } from './create-song.dto';\n\nexport class UpdateSongDto extends PartialType(CreateSongDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n      providers: [SongsService],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private readonly songsService: SongsService) {}\n\n  @Post()\n  create(@Body() createSongDto: Prisma.SongCreateInput) {\n    return this.songsService.create(createSongDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.songsService.findOne({ id: +id });\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.songsService.update({ id: +id }, updateSongDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.songsService.remove({ id: +id });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { SongsController } from './songs.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService, PrismaService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class SongsService {\n  constructor(private prisma: PrismaService) {}\n  create(createSongDto: Prisma.SongUncheckedCreateInput) {\n    return this.prisma.song.create({\n      data: createSongDto,\n    });\n  }\n\n  findAll() {\n    return this.prisma.song.findMany({ include: { artist: true } });\n  }\n\n  findOne(songWhereUniqueInput: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.findUnique({ where: songWhereUniqueInput });\n  }\n\n  update(\n    where: Prisma.SongWhereUniqueInput,\n    updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.prisma.song.update({\n      where,\n      data: updateSongDto,\n    });\n  }\n\n  remove(where: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.delete({ where });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/dto/create-user.dto.ts",
    "content": "export class CreateUserDto {\n  name: string;\n  photo: string;\n  phone: string;\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/dto/update-user.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateUserDto } from './create-user.dto';\n\nexport class UpdateUserDto extends PartialType(CreateUserDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/users.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersController } from './users.controller';\nimport { UsersService } from './users.service';\n\ndescribe('UsersController', () => {\n  let controller: UsersController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [UsersController],\n      providers: [UsersService],\n    }).compile();\n\n    controller = module.get<UsersController>(UsersController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/users.controller.ts",
    "content": "import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\n@Controller('users')\nexport class UsersController {\n  constructor(private readonly usersService: UsersService) {}\n\n  @Post()\n  create(@Body() createUserDto: CreateUserDto) {\n    return this.usersService.create(createUserDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.usersService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.usersService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {\n    return this.usersService.update(+id, updateUserDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.usersService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { UsersController } from './users.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [UsersController],\n  providers: [UsersService, PrismaService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/src/users/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\nimport { PrismaService } from '../prisma.service';\n\n@Injectable()\nexport class UsersService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createUserDto: CreateUserDto) {\n    return this.prisma.user.create({\n      data: {\n        name: createUserDto.name,\n        profile: {\n          create: {\n            phone: createUserDto.phone,\n            photo: createUserDto.photo,\n          },\n        },\n      },\n    });\n  }\n\n  findAll() {\n    return this.prisma.user.findMany({ include: { profile: true } });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} user`;\n  }\n\n  update(id: number, updateUserDto: UpdateUserDto) {\n    return `This action updates a #${id} user`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} user`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/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": "module-20-prisma-integration/lesson-07/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-07/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/http-client.http",
    "content": "### Create Song\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n    \"title\" : \"Animals\",\n    \"artistId\":1\n}\n\n### FETCH ALL SONGS\n\nGET http://localhost:3000/songs\n\n\n### FETCH SONG BY ID\nGET http://localhost:3000/songs/2\n\n\n### UPDATE SONG BY ID\nPATCH http://localhost:3000/songs/3\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVING ME\"\n}\n\n\n### DELETE Song by id\nDELETE http://localhost:3000/songs/3\n\n### Create Artist\nPOST http://localhost:3000/artists\nContent-Type: application/json\n\n{\n    \"name\" : \"Avicci\"\n}\n\n### Create User\nPOST http://localhost:3000/users\nContent-Type: application/json\n\n{\n    \"name\" : \"Jane Doe\",\n    \"photo\": \"some-api.com/photos/1.jpg\",\n    \"phone\": \"+9234344433\"\n}\n\n### FETCH Users\nGET http://localhost:3000/users\n\n### Create POST\nPOST http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"title\": \"One to Many Relation\",\n  \"categories\": {\n    \"create\": [\n      {\n        \"assignedBy\": \"Jane\",\n        \"asignedAt\": \"2023-08-01T10:03:38.016Z\",\n        \"category\": {\n          \"create\": {\n            \"name\": \"Prisma\"\n          }\n        }\n      },\n      {\n        \"assignedBy\": \"Jane\",\n        \"asignedAt\": \"2023-08-01T10:03:38.016Z\",\n        \"category\": {\n          \"create\": {\n            \"name\": \"Nest.js\"\n          }\n        }\n      }\n    ]\n  }\n}\n\n### Create Post with Existing categories\nPOST http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"title\": \"Transactions in Prisma\",\n  \"categories\": {\n    \"create\": [\n      {\n        \"assignedBy\": \"Bob\",\n        \"asignedAt\": \"2023-08-01T10:07:00.918Z\",\n        \"category\": {\n          \"connect\": {\n            \"id\": 1\n          }\n        }\n      },\n      {\n        \"assignedBy\": \"Bob\",\n        \"asignedAt\": \"2023-08-01T10:07:00.918Z\",\n        \"category\": {\n          \"connect\": {\n            \"id\": 2\n          }\n        }\n      }\n    ]\n  }\n}\n\n### FETCH ALL THE POSTS WITH NEST.JS CATEGORY\nGET http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"categories\": {\n    \"some\": {\n      \"category\": {\n        \"name\": \"Nest.js\"\n      }\n    }\n  }\n}\n\n### CREATE NEW APPLICATION\nPOST http://localhost:3000/applications\nContent-Type: application/json\n\n{\n  \"email\": \"jane1@gmail.com\",\n  \"name\": \"Jone Doe\",\n  \"address\": {\n    \"create\": {\n      \"city\": \"New York\",\n      \"country\": \"USA\",\n      \"zip\": \"34443\"\n    }\n  },\n  \"applications\": {\n    \"create\": [\n      {\n        \"amount\": 32224,\n        \"tenure\": \"5 Years\",\n        \"type\": \"BUSINESS_FINANCING\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/20230801082432_add_artists/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Song\" ADD COLUMN     \"artistId\" INTEGER;\n\n-- CreateTable\nCREATE TABLE \"Artist\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Artist_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- AddForeignKey\nALTER TABLE \"Song\" ADD CONSTRAINT \"Song_artistId_fkey\" FOREIGN KEY (\"artistId\") REFERENCES \"Artist\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/20230801091013_one_to_one/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"User\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"User_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Profile\" (\n    \"id\" SERIAL NOT NULL,\n    \"userId\" INTEGER NOT NULL,\n    \"photo\" TEXT NOT NULL,\n    \"phone\" TEXT NOT NULL,\n\n    CONSTRAINT \"Profile_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Profile_userId_key\" ON \"Profile\"(\"userId\");\n\n-- AddForeignKey\nALTER TABLE \"Profile\" ADD CONSTRAINT \"Profile_userId_fkey\" FOREIGN KEY (\"userId\") REFERENCES \"User\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/20230802074328_many_to_many/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Post\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Post_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Category\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Category_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"CategoriesOnPosts\" (\n    \"postId\" INTEGER NOT NULL,\n    \"categoryId\" INTEGER NOT NULL,\n    \"asignedAt\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    \"assignedBy\" TEXT NOT NULL,\n\n    CONSTRAINT \"CategoriesOnPosts_pkey\" PRIMARY KEY (\"postId\",\"categoryId\")\n);\n\n-- AddForeignKey\nALTER TABLE \"CategoriesOnPosts\" ADD CONSTRAINT \"CategoriesOnPosts_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES \"Post\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n\n-- AddForeignKey\nALTER TABLE \"CategoriesOnPosts\" ADD CONSTRAINT \"CategoriesOnPosts_categoryId_fkey\" FOREIGN KEY (\"categoryId\") REFERENCES \"Category\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/20230802081727_nested_queries/migration.sql",
    "content": "-- CreateEnum\nCREATE TYPE \"APPLICATION_TYPE\" AS ENUM ('LOAN', 'CAR_FINANCING', 'BUSINESS_FINANCING');\n\n-- CreateTable\nCREATE TABLE \"Customer\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n    \"email\" TEXT NOT NULL,\n    \"addressId\" INTEGER,\n\n    CONSTRAINT \"Customer_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Address\" (\n    \"id\" SERIAL NOT NULL,\n    \"zip\" TEXT,\n    \"city\" TEXT NOT NULL,\n    \"country\" TEXT NOT NULL,\n\n    CONSTRAINT \"Address_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Application\" (\n    \"id\" SERIAL NOT NULL,\n    \"type\" \"APPLICATION_TYPE\" NOT NULL,\n    \"tenure\" TEXT NOT NULL,\n    \"amount\" INTEGER NOT NULL,\n    \"customerId\" INTEGER,\n\n    CONSTRAINT \"Application_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Customer_email_key\" ON \"Customer\"(\"email\");\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Customer_addressId_key\" ON \"Customer\"(\"addressId\");\n\n-- AddForeignKey\nALTER TABLE \"Customer\" ADD CONSTRAINT \"Customer_addressId_fkey\" FOREIGN KEY (\"addressId\") REFERENCES \"Address\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n\n-- AddForeignKey\nALTER TABLE \"Application\" ADD CONSTRAINT \"Application_customerId_fkey\" FOREIGN KEY (\"customerId\") REFERENCES \"Customer\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/20230802083400_default_value_for_type/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Application\" ALTER COLUMN \"type\" SET DEFAULT 'LOAN';\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-08/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id       Int     @id @default(autoincrement())\n  title    String\n  artist   Artist? @relation(fields: [artistId], references: [id])\n  artistId Int?\n}\n\nmodel Artist {\n  id    Int    @id @default(autoincrement())\n  name  String\n  songs Song[]\n}\n\nmodel User {\n  id   Int    @id @default(autoincrement())\n  name String\n\n  profile Profile?\n}\n\nmodel Profile {\n  id     Int    @id @default(autoincrement())\n  user   User   @relation(fields: [userId], references: [id])\n  userId Int    @unique\n  photo  String\n  phone  String\n}\n\nmodel Post {\n  id         Int                 @id @default(autoincrement())\n  title      String\n  categories CategoriesOnPosts[]\n}\n\nmodel Category {\n  id    Int                 @id @default(autoincrement())\n  name  String\n  posts CategoriesOnPosts[]\n}\n\nmodel CategoriesOnPosts {\n  post       Post     @relation(fields: [postId], references: [id])\n  postId     Int\n  category   Category @relation(fields: [categoryId], references: [id])\n  categoryId Int\n\n  asignedAt  DateTime @default(now())\n  assignedBy String\n\n  @@id([postId, categoryId])\n}\n\n// You have to create Customer, Address and the Application Model\n// One to one relation with Customer and Address\n// One to many relation with Customer and Application\n\nmodel Customer {\n  id           Int           @id @default(autoincrement())\n  name         String\n  email        String        @unique\n  address      Address?      @relation(fields: [addressId], references: [id])\n  applications Application[]\n  addressId    Int?          @unique\n}\n\nmodel Address {\n  id       Int       @id @default(autoincrement())\n  zip      String?\n  city     String\n  country  String\n  Customer Customer?\n}\n\nenum APPLICATION_TYPE {\n  LOAN\n  CAR_FINANCING\n  BUSINESS_FINANCING\n}\n\nmodel Application {\n  id     Int              @id @default(autoincrement())\n  type   APPLICATION_TYPE @default(LOAN)\n  tenure String\n  amount Int\n\n  Customer   Customer? @relation(fields: [customerId], references: [id])\n  customerId Int?\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/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": "module-20-prisma-integration/lesson-08/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { UsersModule } from './users/users.module';\nimport { PostsModule } from './posts/posts.module';\nimport { ApplicationsModule } from './applications/applications.module';\n\n@Module({\n  imports: [SongsModule, ArtistsModule, UsersModule, PostsModule, ApplicationsModule],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/applications.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ApplicationsController } from './applications.controller';\nimport { ApplicationsService } from './applications.service';\n\ndescribe('ApplicationsController', () => {\n  let controller: ApplicationsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ApplicationsController],\n      providers: [ApplicationsService],\n    }).compile();\n\n    controller = module.get<ApplicationsController>(ApplicationsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/applications.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ApplicationsService } from './applications.service';\nimport { CreateApplicationDto } from './dto/create-application.dto';\nimport { UpdateApplicationDto } from './dto/update-application.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('applications')\nexport class ApplicationsController {\n  constructor(private readonly applicationsService: ApplicationsService) {}\n\n  @Post()\n  create(@Body() createApplicationDto: Prisma.CustomerCreateInput) {\n    return this.applicationsService.create(createApplicationDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.applicationsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.applicationsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateApplicationDto: UpdateApplicationDto,\n  ) {\n    return this.applicationsService.update(+id, updateApplicationDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.applicationsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/applications.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ApplicationsService } from './applications.service';\nimport { ApplicationsController } from './applications.controller';\n\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ApplicationsController],\n  providers: [ApplicationsService, PrismaService],\n})\nexport class ApplicationsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/applications.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ApplicationsService } from './applications.service';\n\ndescribe('ApplicationsService', () => {\n  let service: ApplicationsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ApplicationsService],\n    }).compile();\n\n    service = module.get<ApplicationsService>(ApplicationsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/applications.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateApplicationDto } from './dto/create-application.dto';\nimport { UpdateApplicationDto } from './dto/update-application.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ApplicationsService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createApplicationDto: Prisma.CustomerCreateInput) {\n    return this.prisma.customer.create({ data: createApplicationDto });\n  }\n\n  findAll() {\n    return `This action returns all applications`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} application`;\n  }\n\n  update(id: number, updateApplicationDto: UpdateApplicationDto) {\n    return `This action updates a #${id} application`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} application`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/dto/create-application.dto.ts",
    "content": "export class CreateApplicationDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/applications/dto/update-application.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateApplicationDto } from './create-application.dto';\n\nexport class UpdateApplicationDto extends PartialType(CreateApplicationDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n      providers: [ArtistsService],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/artists.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('artists')\nexport class ArtistsController {\n  constructor(private readonly artistsService: ArtistsService) {}\n\n  @Post()\n  create(@Body() createArtistDto: Prisma.ArtistCreateInput) {\n    return this.artistsService.create(createArtistDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.artistsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.artistsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateArtistDto: UpdateArtistDto) {\n    return this.artistsService.update(+id, updateArtistDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.artistsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ArtistsController],\n  providers: [ArtistsService, PrismaService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateArtistDto } from './dto/create-artist.dto';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(private prisma: PrismaService) {}\n  create(createArtistDto: Prisma.ArtistCreateInput) {\n    return this.prisma.artist.create({\n      data: createArtistDto,\n    });\n  }\n\n  findAll() {\n    return `This action returns all artists`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} artist`;\n  }\n\n  update(id: number, updateArtistDto: UpdateArtistDto) {\n    return `This action updates a #${id} artist`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} artist`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/dto/create-artist.dto.ts",
    "content": "export class CreateArtistDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/artists/dto/update-artist.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateArtistDto } from './create-artist.dto';\n\nexport class UpdateArtistDto extends PartialType(CreateArtistDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/dto/create-post.dto.ts",
    "content": "export class CreatePostDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/dto/update-post.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreatePostDto } from './create-post.dto';\n\nexport class UpdatePostDto extends PartialType(CreatePostDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/posts.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { PostsController } from './posts.controller';\nimport { PostsService } from './posts.service';\n\ndescribe('PostsController', () => {\n  let controller: PostsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [PostsController],\n      providers: [PostsService],\n    }).compile();\n\n    controller = module.get<PostsController>(PostsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/posts.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { CreatePostDto } from './dto/create-post.dto';\nimport { UpdatePostDto } from './dto/update-post.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('posts')\nexport class PostsController {\n  constructor(private readonly postsService: PostsService) {}\n\n  @Post()\n  @Post()\n  create(@Body() createPostDto: Prisma.PostCreateInput) {\n    return this.postsService.create(createPostDto);\n  }\n  @Get()\n  findAll(\n    @Body()\n    where: Prisma.PostWhereUniqueInput,\n  ) {\n    return this.postsService.findAll(where);\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.postsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {\n    return this.postsService.update(+id, updatePostDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.postsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/posts.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { PostsController } from './posts.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [PostsController],\n  providers: [PostsService, PrismaService],\n})\nexport class PostsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/posts.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { PostsService } from './posts.service';\n\ndescribe('PostsService', () => {\n  let service: PostsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [PostsService],\n    }).compile();\n\n    service = module.get<PostsService>(PostsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/posts/posts.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreatePostDto } from './dto/create-post.dto';\nimport { UpdatePostDto } from './dto/update-post.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class PostsService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createPostDto: Prisma.PostCreateInput) {\n    return this.prisma.post.create({ data: createPostDto });\n  }\n\n  findAll(where: Prisma.PostWhereUniqueInput) {\n    return this.prisma.post.findMany({\n      where,\n    });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} post`;\n  }\n\n  update(id: number, updatePostDto: UpdatePostDto) {\n    return `This action updates a #${id} post`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} post`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/dto/create-song.dto.ts",
    "content": "export class CreateSongDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/dto/update-song.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateSongDto } from './create-song.dto';\n\nexport class UpdateSongDto extends PartialType(CreateSongDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n      providers: [SongsService],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private readonly songsService: SongsService) {}\n\n  @Post()\n  create(@Body() createSongDto: Prisma.SongCreateInput) {\n    return this.songsService.create(createSongDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.songsService.findOne({ id: +id });\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.songsService.update({ id: +id }, updateSongDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.songsService.remove({ id: +id });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { SongsController } from './songs.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService, PrismaService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class SongsService {\n  constructor(private prisma: PrismaService) {}\n  create(createSongDto: Prisma.SongUncheckedCreateInput) {\n    return this.prisma.song.create({\n      data: createSongDto,\n    });\n  }\n\n  findAll() {\n    return this.prisma.song.findMany({ include: { artist: true } });\n  }\n\n  findOne(songWhereUniqueInput: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.findUnique({ where: songWhereUniqueInput });\n  }\n\n  update(\n    where: Prisma.SongWhereUniqueInput,\n    updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.prisma.song.update({\n      where,\n      data: updateSongDto,\n    });\n  }\n\n  remove(where: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.delete({ where });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/dto/create-user.dto.ts",
    "content": "export class CreateUserDto {\n  name: string;\n  photo: string;\n  phone: string;\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/dto/update-user.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateUserDto } from './create-user.dto';\n\nexport class UpdateUserDto extends PartialType(CreateUserDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/users.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersController } from './users.controller';\nimport { UsersService } from './users.service';\n\ndescribe('UsersController', () => {\n  let controller: UsersController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [UsersController],\n      providers: [UsersService],\n    }).compile();\n\n    controller = module.get<UsersController>(UsersController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/users.controller.ts",
    "content": "import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\n@Controller('users')\nexport class UsersController {\n  constructor(private readonly usersService: UsersService) {}\n\n  @Post()\n  create(@Body() createUserDto: CreateUserDto) {\n    return this.usersService.create(createUserDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.usersService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.usersService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {\n    return this.usersService.update(+id, updateUserDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.usersService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { UsersController } from './users.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [UsersController],\n  providers: [UsersService, PrismaService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/src/users/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\nimport { PrismaService } from '../prisma.service';\n\n@Injectable()\nexport class UsersService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createUserDto: CreateUserDto) {\n    return this.prisma.user.create({\n      data: {\n        name: createUserDto.name,\n        profile: {\n          create: {\n            phone: createUserDto.phone,\n            photo: createUserDto.photo,\n          },\n        },\n      },\n    });\n  }\n\n  findAll() {\n    return this.prisma.user.findMany({ include: { profile: true } });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} user`;\n  }\n\n  update(id: number, updateUserDto: UpdateUserDto) {\n    return `This action updates a #${id} user`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} user`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/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": "module-20-prisma-integration/lesson-08/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-08/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/http-client.http",
    "content": "### Create Song\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n    \"title\" : \"Animals\",\n    \"artistId\":1\n}\n\n### FETCH ALL SONGS\n\nGET http://localhost:3000/songs\n\n\n### FETCH SONG BY ID\nGET http://localhost:3000/songs/2\n\n\n### UPDATE SONG BY ID\nPATCH http://localhost:3000/songs/3\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVING ME\"\n}\n\n\n### DELETE Song by id\nDELETE http://localhost:3000/songs/3\n\n### Create Artist\nPOST http://localhost:3000/artists\nContent-Type: application/json\n\n{\n    \"name\" : \"Avicci\"\n}\n\n### Create User\nPOST http://localhost:3000/users\nContent-Type: application/json\n\n{\n    \"name\" : \"Jane Doe\",\n    \"photo\": \"some-api.com/photos/1.jpg\",\n    \"phone\": \"+9234344433\"\n}\n\n### FETCH Users\nGET http://localhost:3000/users\n\n### Create POST\nPOST http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"title\": \"One to Many Relation\",\n  \"categories\": {\n    \"create\": [\n      {\n        \"assignedBy\": \"Jane\",\n        \"asignedAt\": \"2023-08-01T10:03:38.016Z\",\n        \"category\": {\n          \"create\": {\n            \"name\": \"Prisma\"\n          }\n        }\n      },\n      {\n        \"assignedBy\": \"Jane\",\n        \"asignedAt\": \"2023-08-01T10:03:38.016Z\",\n        \"category\": {\n          \"create\": {\n            \"name\": \"Nest.js\"\n          }\n        }\n      }\n    ]\n  }\n}\n\n### Create Post with Existing categories\nPOST http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"title\": \"Transactions in Prisma\",\n  \"categories\": {\n    \"create\": [\n      {\n        \"assignedBy\": \"Bob\",\n        \"asignedAt\": \"2023-08-01T10:07:00.918Z\",\n        \"category\": {\n          \"connect\": {\n            \"id\": 1\n          }\n        }\n      },\n      {\n        \"assignedBy\": \"Bob\",\n        \"asignedAt\": \"2023-08-01T10:07:00.918Z\",\n        \"category\": {\n          \"connect\": {\n            \"id\": 2\n          }\n        }\n      }\n    ]\n  }\n}\n\n### FETCH ALL THE POSTS WITH NEST.JS CATEGORY\nGET http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"categories\": {\n    \"some\": {\n      \"category\": {\n        \"name\": \"Nest.js\"\n      }\n    }\n  }\n}\n\n### CREATE NEW APPLICATION\nPOST http://localhost:3000/applications\nContent-Type: application/json\n\n{\n  \"email\": \"jane1@gmail.com\",\n  \"name\": \"Jone Doe\",\n  \"address\": {\n    \"create\": {\n      \"city\": \"New York\",\n      \"country\": \"USA\",\n      \"zip\": \"34443\"\n    }\n  },\n  \"applications\": {\n    \"create\": [\n      {\n        \"amount\": 32224,\n        \"tenure\": \"5 Years\",\n        \"type\": \"BUSINESS_FINANCING\"\n      }\n    ]\n  }\n}\n\n### SEQUENTIAL QUERY\nGET http://localhost:3000/sequential\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/20230801082432_add_artists/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Song\" ADD COLUMN     \"artistId\" INTEGER;\n\n-- CreateTable\nCREATE TABLE \"Artist\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Artist_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- AddForeignKey\nALTER TABLE \"Song\" ADD CONSTRAINT \"Song_artistId_fkey\" FOREIGN KEY (\"artistId\") REFERENCES \"Artist\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/20230801091013_one_to_one/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"User\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"User_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Profile\" (\n    \"id\" SERIAL NOT NULL,\n    \"userId\" INTEGER NOT NULL,\n    \"photo\" TEXT NOT NULL,\n    \"phone\" TEXT NOT NULL,\n\n    CONSTRAINT \"Profile_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Profile_userId_key\" ON \"Profile\"(\"userId\");\n\n-- AddForeignKey\nALTER TABLE \"Profile\" ADD CONSTRAINT \"Profile_userId_fkey\" FOREIGN KEY (\"userId\") REFERENCES \"User\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/20230802074328_many_to_many/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Post\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Post_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Category\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Category_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"CategoriesOnPosts\" (\n    \"postId\" INTEGER NOT NULL,\n    \"categoryId\" INTEGER NOT NULL,\n    \"asignedAt\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    \"assignedBy\" TEXT NOT NULL,\n\n    CONSTRAINT \"CategoriesOnPosts_pkey\" PRIMARY KEY (\"postId\",\"categoryId\")\n);\n\n-- AddForeignKey\nALTER TABLE \"CategoriesOnPosts\" ADD CONSTRAINT \"CategoriesOnPosts_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES \"Post\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n\n-- AddForeignKey\nALTER TABLE \"CategoriesOnPosts\" ADD CONSTRAINT \"CategoriesOnPosts_categoryId_fkey\" FOREIGN KEY (\"categoryId\") REFERENCES \"Category\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/20230802081727_nested_queries/migration.sql",
    "content": "-- CreateEnum\nCREATE TYPE \"APPLICATION_TYPE\" AS ENUM ('LOAN', 'CAR_FINANCING', 'BUSINESS_FINANCING');\n\n-- CreateTable\nCREATE TABLE \"Customer\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n    \"email\" TEXT NOT NULL,\n    \"addressId\" INTEGER,\n\n    CONSTRAINT \"Customer_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Address\" (\n    \"id\" SERIAL NOT NULL,\n    \"zip\" TEXT,\n    \"city\" TEXT NOT NULL,\n    \"country\" TEXT NOT NULL,\n\n    CONSTRAINT \"Address_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Application\" (\n    \"id\" SERIAL NOT NULL,\n    \"type\" \"APPLICATION_TYPE\" NOT NULL,\n    \"tenure\" TEXT NOT NULL,\n    \"amount\" INTEGER NOT NULL,\n    \"customerId\" INTEGER,\n\n    CONSTRAINT \"Application_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Customer_email_key\" ON \"Customer\"(\"email\");\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Customer_addressId_key\" ON \"Customer\"(\"addressId\");\n\n-- AddForeignKey\nALTER TABLE \"Customer\" ADD CONSTRAINT \"Customer_addressId_fkey\" FOREIGN KEY (\"addressId\") REFERENCES \"Address\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n\n-- AddForeignKey\nALTER TABLE \"Application\" ADD CONSTRAINT \"Application_customerId_fkey\" FOREIGN KEY (\"customerId\") REFERENCES \"Customer\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/20230802083400_default_value_for_type/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Application\" ALTER COLUMN \"type\" SET DEFAULT 'LOAN';\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-09/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id       Int     @id @default(autoincrement())\n  title    String\n  artist   Artist? @relation(fields: [artistId], references: [id])\n  artistId Int?\n}\n\nmodel Artist {\n  id    Int    @id @default(autoincrement())\n  name  String\n  songs Song[]\n}\n\nmodel User {\n  id   Int    @id @default(autoincrement())\n  name String\n\n  profile Profile?\n}\n\nmodel Profile {\n  id     Int    @id @default(autoincrement())\n  user   User   @relation(fields: [userId], references: [id])\n  userId Int    @unique\n  photo  String\n  phone  String\n}\n\nmodel Post {\n  id         Int                 @id @default(autoincrement())\n  title      String\n  categories CategoriesOnPosts[]\n}\n\nmodel Category {\n  id    Int                 @id @default(autoincrement())\n  name  String\n  posts CategoriesOnPosts[]\n}\n\nmodel CategoriesOnPosts {\n  post       Post     @relation(fields: [postId], references: [id])\n  postId     Int\n  category   Category @relation(fields: [categoryId], references: [id])\n  categoryId Int\n\n  asignedAt  DateTime @default(now())\n  assignedBy String\n\n  @@id([postId, categoryId])\n}\n\n// You have to create Customer, Address and the Application Model\n// One to one relation with Customer and Address\n// One to many relation with Customer and Application\n\nmodel Customer {\n  id           Int           @id @default(autoincrement())\n  name         String\n  email        String        @unique\n  address      Address?      @relation(fields: [addressId], references: [id])\n  applications Application[]\n  addressId    Int?          @unique\n}\n\nmodel Address {\n  id       Int       @id @default(autoincrement())\n  zip      String?\n  city     String\n  country  String\n  Customer Customer?\n}\n\nenum APPLICATION_TYPE {\n  LOAN\n  CAR_FINANCING\n  BUSINESS_FINANCING\n}\n\nmodel Application {\n  id     Int              @id @default(autoincrement())\n  type   APPLICATION_TYPE @default(LOAN)\n  tenure String\n  amount Int\n\n  Customer   Customer? @relation(fields: [customerId], references: [id])\n  customerId Int?\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/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": "module-20-prisma-integration/lesson-09/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { PrismaService } from './prisma.service';\n\n@Controller()\nexport class AppController {\n  constructor(\n    private readonly appService: AppService,\n    private prisma: PrismaService,\n  ) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('sequential')\n  getSequentialResults() {\n    return this.prisma.$transaction([\n      this.prisma.post.findMany(),\n      this.prisma.artist.findMany(),\n      this.prisma.song.findMany(),\n      this.prisma.application.findMany(),\n    ]);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { UsersModule } from './users/users.module';\nimport { PostsModule } from './posts/posts.module';\nimport { ApplicationsModule } from './applications/applications.module';\nimport { PrismaService } from './prisma.service';\n\n@Module({\n  imports: [\n    SongsModule,\n    ArtistsModule,\n    UsersModule,\n    PostsModule,\n    ApplicationsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService, PrismaService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/applications.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ApplicationsController } from './applications.controller';\nimport { ApplicationsService } from './applications.service';\n\ndescribe('ApplicationsController', () => {\n  let controller: ApplicationsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ApplicationsController],\n      providers: [ApplicationsService],\n    }).compile();\n\n    controller = module.get<ApplicationsController>(ApplicationsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/applications.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ApplicationsService } from './applications.service';\nimport { CreateApplicationDto } from './dto/create-application.dto';\nimport { UpdateApplicationDto } from './dto/update-application.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('applications')\nexport class ApplicationsController {\n  constructor(private readonly applicationsService: ApplicationsService) {}\n\n  @Post()\n  create(@Body() createApplicationDto: Prisma.CustomerCreateInput) {\n    return this.applicationsService.create(createApplicationDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.applicationsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.applicationsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateApplicationDto: UpdateApplicationDto,\n  ) {\n    return this.applicationsService.update(+id, updateApplicationDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.applicationsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/applications.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ApplicationsService } from './applications.service';\nimport { ApplicationsController } from './applications.controller';\n\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ApplicationsController],\n  providers: [ApplicationsService, PrismaService],\n})\nexport class ApplicationsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/applications.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ApplicationsService } from './applications.service';\n\ndescribe('ApplicationsService', () => {\n  let service: ApplicationsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ApplicationsService],\n    }).compile();\n\n    service = module.get<ApplicationsService>(ApplicationsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/applications.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateApplicationDto } from './dto/create-application.dto';\nimport { UpdateApplicationDto } from './dto/update-application.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ApplicationsService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createApplicationDto: Prisma.CustomerCreateInput) {\n    return this.prisma.customer.create({ data: createApplicationDto });\n  }\n\n  findAll() {\n    return `This action returns all applications`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} application`;\n  }\n\n  update(id: number, updateApplicationDto: UpdateApplicationDto) {\n    return `This action updates a #${id} application`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} application`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/dto/create-application.dto.ts",
    "content": "export class CreateApplicationDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/applications/dto/update-application.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateApplicationDto } from './create-application.dto';\n\nexport class UpdateApplicationDto extends PartialType(CreateApplicationDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n      providers: [ArtistsService],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/artists.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('artists')\nexport class ArtistsController {\n  constructor(private readonly artistsService: ArtistsService) {}\n\n  @Post()\n  create(@Body() createArtistDto: Prisma.ArtistCreateInput) {\n    return this.artistsService.create(createArtistDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.artistsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.artistsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateArtistDto: UpdateArtistDto) {\n    return this.artistsService.update(+id, updateArtistDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.artistsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ArtistsController],\n  providers: [ArtistsService, PrismaService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateArtistDto } from './dto/create-artist.dto';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(private prisma: PrismaService) {}\n  create(createArtistDto: Prisma.ArtistCreateInput) {\n    return this.prisma.artist.create({\n      data: createArtistDto,\n    });\n  }\n\n  findAll() {\n    return `This action returns all artists`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} artist`;\n  }\n\n  update(id: number, updateArtistDto: UpdateArtistDto) {\n    return `This action updates a #${id} artist`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} artist`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/dto/create-artist.dto.ts",
    "content": "export class CreateArtistDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/artists/dto/update-artist.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateArtistDto } from './create-artist.dto';\n\nexport class UpdateArtistDto extends PartialType(CreateArtistDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/dto/create-post.dto.ts",
    "content": "export class CreatePostDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/dto/update-post.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreatePostDto } from './create-post.dto';\n\nexport class UpdatePostDto extends PartialType(CreatePostDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/posts.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { PostsController } from './posts.controller';\nimport { PostsService } from './posts.service';\n\ndescribe('PostsController', () => {\n  let controller: PostsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [PostsController],\n      providers: [PostsService],\n    }).compile();\n\n    controller = module.get<PostsController>(PostsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/posts.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { CreatePostDto } from './dto/create-post.dto';\nimport { UpdatePostDto } from './dto/update-post.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('posts')\nexport class PostsController {\n  constructor(private readonly postsService: PostsService) {}\n\n  @Post()\n  @Post()\n  create(@Body() createPostDto: Prisma.PostCreateInput) {\n    return this.postsService.create(createPostDto);\n  }\n  @Get()\n  findAll(\n    @Body()\n    where: Prisma.PostWhereUniqueInput,\n  ) {\n    return this.postsService.findAll(where);\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.postsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {\n    return this.postsService.update(+id, updatePostDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.postsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/posts.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { PostsController } from './posts.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [PostsController],\n  providers: [PostsService, PrismaService],\n})\nexport class PostsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/posts.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { PostsService } from './posts.service';\n\ndescribe('PostsService', () => {\n  let service: PostsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [PostsService],\n    }).compile();\n\n    service = module.get<PostsService>(PostsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/posts/posts.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreatePostDto } from './dto/create-post.dto';\nimport { UpdatePostDto } from './dto/update-post.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class PostsService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createPostDto: Prisma.PostCreateInput) {\n    return this.prisma.post.create({ data: createPostDto });\n  }\n\n  findAll(where: Prisma.PostWhereUniqueInput) {\n    return this.prisma.post.findMany({\n      where,\n    });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} post`;\n  }\n\n  update(id: number, updatePostDto: UpdatePostDto) {\n    return `This action updates a #${id} post`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} post`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/dto/create-song.dto.ts",
    "content": "export class CreateSongDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/dto/update-song.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateSongDto } from './create-song.dto';\n\nexport class UpdateSongDto extends PartialType(CreateSongDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n      providers: [SongsService],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private readonly songsService: SongsService) {}\n\n  @Post()\n  create(@Body() createSongDto: Prisma.SongCreateInput) {\n    return this.songsService.create(createSongDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.songsService.findOne({ id: +id });\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.songsService.update({ id: +id }, updateSongDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.songsService.remove({ id: +id });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { SongsController } from './songs.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService, PrismaService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class SongsService {\n  constructor(private prisma: PrismaService) {}\n  create(createSongDto: Prisma.SongUncheckedCreateInput) {\n    return this.prisma.song.create({\n      data: createSongDto,\n    });\n  }\n\n  findAll() {\n    return this.prisma.song.findMany({ include: { artist: true } });\n  }\n\n  findOne(songWhereUniqueInput: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.findUnique({ where: songWhereUniqueInput });\n  }\n\n  update(\n    where: Prisma.SongWhereUniqueInput,\n    updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.prisma.song.update({\n      where,\n      data: updateSongDto,\n    });\n  }\n\n  remove(where: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.delete({ where });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/dto/create-user.dto.ts",
    "content": "export class CreateUserDto {\n  name: string;\n  photo: string;\n  phone: string;\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/dto/update-user.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateUserDto } from './create-user.dto';\n\nexport class UpdateUserDto extends PartialType(CreateUserDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/users.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersController } from './users.controller';\nimport { UsersService } from './users.service';\n\ndescribe('UsersController', () => {\n  let controller: UsersController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [UsersController],\n      providers: [UsersService],\n    }).compile();\n\n    controller = module.get<UsersController>(UsersController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/users.controller.ts",
    "content": "import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\n@Controller('users')\nexport class UsersController {\n  constructor(private readonly usersService: UsersService) {}\n\n  @Post()\n  create(@Body() createUserDto: CreateUserDto) {\n    return this.usersService.create(createUserDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.usersService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.usersService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {\n    return this.usersService.update(+id, updateUserDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.usersService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { UsersController } from './users.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [UsersController],\n  providers: [UsersService, PrismaService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/src/users/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\nimport { PrismaService } from '../prisma.service';\n\n@Injectable()\nexport class UsersService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createUserDto: CreateUserDto) {\n    return this.prisma.user.create({\n      data: {\n        name: createUserDto.name,\n        profile: {\n          create: {\n            phone: createUserDto.phone,\n            photo: createUserDto.photo,\n          },\n        },\n      },\n    });\n  }\n\n  findAll() {\n    return this.prisma.user.findMany({ include: { profile: true } });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} user`;\n  }\n\n  update(id: number, updateUserDto: UpdateUserDto) {\n    return `This action updates a #${id} user`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} user`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/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": "module-20-prisma-integration/lesson-09/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-09/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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\n.env"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/http-client.http",
    "content": "### Create Song\nPOST http://localhost:3000/songs\nContent-Type: application/json\n\n{\n    \"title\" : \"Animals\",\n    \"artistId\":1\n}\n\n### FETCH ALL SONGS\n\nGET http://localhost:3000/songs\n\n\n### FETCH SONG BY ID\nGET http://localhost:3000/songs/2\n\n\n### UPDATE SONG BY ID\nPATCH http://localhost:3000/songs/3\nContent-Type: application/json\n\n{\n    \"title\" : \"LOVING ME\"\n}\n\n\n### DELETE Song by id\nDELETE http://localhost:3000/songs/3\n\n### Create Artist\nPOST http://localhost:3000/artists\nContent-Type: application/json\n\n{\n    \"name\" : \"Avicci\"\n}\n\n### Create User\nPOST http://localhost:3000/users\nContent-Type: application/json\n\n{\n    \"name\" : \"Jane Doe\",\n    \"photo\": \"some-api.com/photos/1.jpg\",\n    \"phone\": \"+9234344433\"\n}\n\n### FETCH Users\nGET http://localhost:3000/users\n\n### Create POST\nPOST http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"title\": \"One to Many Relation\",\n  \"categories\": {\n    \"create\": [\n      {\n        \"assignedBy\": \"Jane\",\n        \"asignedAt\": \"2023-08-01T10:03:38.016Z\",\n        \"category\": {\n          \"create\": {\n            \"name\": \"Prisma\"\n          }\n        }\n      },\n      {\n        \"assignedBy\": \"Jane\",\n        \"asignedAt\": \"2023-08-01T10:03:38.016Z\",\n        \"category\": {\n          \"create\": {\n            \"name\": \"Nest.js\"\n          }\n        }\n      }\n    ]\n  }\n}\n\n### Create Post with Existing categories\nPOST http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"title\": \"Transactions in Prisma\",\n  \"categories\": {\n    \"create\": [\n      {\n        \"assignedBy\": \"Bob\",\n        \"asignedAt\": \"2023-08-01T10:07:00.918Z\",\n        \"category\": {\n          \"connect\": {\n            \"id\": 1\n          }\n        }\n      },\n      {\n        \"assignedBy\": \"Bob\",\n        \"asignedAt\": \"2023-08-01T10:07:00.918Z\",\n        \"category\": {\n          \"connect\": {\n            \"id\": 2\n          }\n        }\n      }\n    ]\n  }\n}\n\n### FETCH ALL THE POSTS WITH NEST.JS CATEGORY\nGET http://localhost:3000/posts\nContent-Type: application/json\n\n{\n  \"categories\": {\n    \"some\": {\n      \"category\": {\n        \"name\": \"Nest.js\"\n      }\n    }\n  }\n}\n\n### CREATE NEW APPLICATION\nPOST http://localhost:3000/applications\nContent-Type: application/json\n\n{\n  \"email\": \"jane1@gmail.com\",\n  \"name\": \"Jone Doe\",\n  \"address\": {\n    \"create\": {\n      \"city\": \"New York\",\n      \"country\": \"USA\",\n      \"zip\": \"34443\"\n    }\n  },\n  \"applications\": {\n    \"create\": [\n      {\n        \"amount\": 32224,\n        \"tenure\": \"5 Years\",\n        \"type\": \"BUSINESS_FINANCING\"\n      }\n    ]\n  }\n}\n\n### SEQUENTIAL QUERY\nGET http://localhost:3000/sequential\n\n\n### Create Account\nPOST http://localhost:3000/accounts\nContent-Type: application/json\n\n{\n  \"title\" : \"Sam\",\n  \"balance\" : 100\n}\n\n### Trasnfer Amount\nPOST http://localhost:3000/accounts/transfer\nContent-Type: application/json\n\n{\n \"sender\" :1,\n \"receiver\" :2,\n \"amount\": 20\n}"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true,\n    \"builder\": \"swc\",\n    \"typeCheck\": true\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/package.json",
    "content": "{\n  \"name\": \"graphql-dev\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"generate:typings\": \"ts-node generate-typings.ts\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\",\n    \"test:e2e:watch\": \"jest --watch --detectOpenHandles --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/mapped-types\": \"*\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@prisma/client\": \"^5.0.0\",\n    \"class-validator\": \"^0.14.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\",\n    \"ts-morph\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@swc/cli\": \"^0.1.62\",\n    \"@swc/core\": \"^1.3.66\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"prisma\": \"^5.0.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230730081110_init/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Song\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Song_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230801082432_add_artists/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Song\" ADD COLUMN     \"artistId\" INTEGER;\n\n-- CreateTable\nCREATE TABLE \"Artist\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Artist_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- AddForeignKey\nALTER TABLE \"Song\" ADD CONSTRAINT \"Song_artistId_fkey\" FOREIGN KEY (\"artistId\") REFERENCES \"Artist\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230801091013_one_to_one/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"User\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"User_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Profile\" (\n    \"id\" SERIAL NOT NULL,\n    \"userId\" INTEGER NOT NULL,\n    \"photo\" TEXT NOT NULL,\n    \"phone\" TEXT NOT NULL,\n\n    CONSTRAINT \"Profile_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Profile_userId_key\" ON \"Profile\"(\"userId\");\n\n-- AddForeignKey\nALTER TABLE \"Profile\" ADD CONSTRAINT \"Profile_userId_fkey\" FOREIGN KEY (\"userId\") REFERENCES \"User\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230802074328_many_to_many/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Post\" (\n    \"id\" SERIAL NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Post_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Category\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n\n    CONSTRAINT \"Category_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"CategoriesOnPosts\" (\n    \"postId\" INTEGER NOT NULL,\n    \"categoryId\" INTEGER NOT NULL,\n    \"asignedAt\" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    \"assignedBy\" TEXT NOT NULL,\n\n    CONSTRAINT \"CategoriesOnPosts_pkey\" PRIMARY KEY (\"postId\",\"categoryId\")\n);\n\n-- AddForeignKey\nALTER TABLE \"CategoriesOnPosts\" ADD CONSTRAINT \"CategoriesOnPosts_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES \"Post\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n\n-- AddForeignKey\nALTER TABLE \"CategoriesOnPosts\" ADD CONSTRAINT \"CategoriesOnPosts_categoryId_fkey\" FOREIGN KEY (\"categoryId\") REFERENCES \"Category\"(\"id\") ON DELETE RESTRICT ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230802081727_nested_queries/migration.sql",
    "content": "-- CreateEnum\nCREATE TYPE \"APPLICATION_TYPE\" AS ENUM ('LOAN', 'CAR_FINANCING', 'BUSINESS_FINANCING');\n\n-- CreateTable\nCREATE TABLE \"Customer\" (\n    \"id\" SERIAL NOT NULL,\n    \"name\" TEXT NOT NULL,\n    \"email\" TEXT NOT NULL,\n    \"addressId\" INTEGER,\n\n    CONSTRAINT \"Customer_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Address\" (\n    \"id\" SERIAL NOT NULL,\n    \"zip\" TEXT,\n    \"city\" TEXT NOT NULL,\n    \"country\" TEXT NOT NULL,\n\n    CONSTRAINT \"Address_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateTable\nCREATE TABLE \"Application\" (\n    \"id\" SERIAL NOT NULL,\n    \"type\" \"APPLICATION_TYPE\" NOT NULL,\n    \"tenure\" TEXT NOT NULL,\n    \"amount\" INTEGER NOT NULL,\n    \"customerId\" INTEGER,\n\n    CONSTRAINT \"Application_pkey\" PRIMARY KEY (\"id\")\n);\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Customer_email_key\" ON \"Customer\"(\"email\");\n\n-- CreateIndex\nCREATE UNIQUE INDEX \"Customer_addressId_key\" ON \"Customer\"(\"addressId\");\n\n-- AddForeignKey\nALTER TABLE \"Customer\" ADD CONSTRAINT \"Customer_addressId_fkey\" FOREIGN KEY (\"addressId\") REFERENCES \"Address\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n\n-- AddForeignKey\nALTER TABLE \"Application\" ADD CONSTRAINT \"Application_customerId_fkey\" FOREIGN KEY (\"customerId\") REFERENCES \"Customer\"(\"id\") ON DELETE SET NULL ON UPDATE CASCADE;\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230802083400_default_value_for_type/migration.sql",
    "content": "-- AlterTable\nALTER TABLE \"Application\" ALTER COLUMN \"type\" SET DEFAULT 'LOAN';\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/20230804090722_add_account/migration.sql",
    "content": "-- CreateTable\nCREATE TABLE \"Account\" (\n    \"id\" SERIAL NOT NULL,\n    \"balance\" DOUBLE PRECISION NOT NULL,\n    \"title\" TEXT NOT NULL,\n\n    CONSTRAINT \"Account_pkey\" PRIMARY KEY (\"id\")\n);\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/migrations/migration_lock.toml",
    "content": "# Please do not edit this file manually\n# It should be added in your version-control system (i.e. Git)\nprovider = \"postgresql\""
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/prisma/schema.prisma",
    "content": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Song {\n  id       Int     @id @default(autoincrement())\n  title    String\n  artist   Artist? @relation(fields: [artistId], references: [id])\n  artistId Int?\n}\n\nmodel Artist {\n  id    Int    @id @default(autoincrement())\n  name  String\n  songs Song[]\n}\n\nmodel User {\n  id   Int    @id @default(autoincrement())\n  name String\n\n  profile Profile?\n}\n\nmodel Profile {\n  id     Int    @id @default(autoincrement())\n  user   User   @relation(fields: [userId], references: [id])\n  userId Int    @unique\n  photo  String\n  phone  String\n}\n\nmodel Post {\n  id         Int                 @id @default(autoincrement())\n  title      String\n  categories CategoriesOnPosts[]\n}\n\nmodel Category {\n  id    Int                 @id @default(autoincrement())\n  name  String\n  posts CategoriesOnPosts[]\n}\n\nmodel CategoriesOnPosts {\n  post       Post     @relation(fields: [postId], references: [id])\n  postId     Int\n  category   Category @relation(fields: [categoryId], references: [id])\n  categoryId Int\n\n  asignedAt  DateTime @default(now())\n  assignedBy String\n\n  @@id([postId, categoryId])\n}\n\n// You have to create Customer, Address and the Application Model\n// One to one relation with Customer and Address\n// One to many relation with Customer and Application\n\nmodel Customer {\n  id           Int           @id @default(autoincrement())\n  name         String\n  email        String        @unique\n  address      Address?      @relation(fields: [addressId], references: [id])\n  applications Application[]\n  addressId    Int?          @unique\n}\n\nmodel Address {\n  id       Int       @id @default(autoincrement())\n  zip      String?\n  city     String\n  country  String\n  Customer Customer?\n}\n\nenum APPLICATION_TYPE {\n  LOAN\n  CAR_FINANCING\n  BUSINESS_FINANCING\n}\n\nmodel Application {\n  id     Int              @id @default(autoincrement())\n  type   APPLICATION_TYPE @default(LOAN)\n  tenure String\n  amount Int\n\n  Customer   Customer? @relation(fields: [customerId], references: [id])\n  customerId Int?\n}\n\nmodel Account {\n  id      Int    @id @default(autoincrement())\n  balance Float\n  title   String\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/accounts.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AccountsController } from './accounts.controller';\nimport { AccountsService } from './accounts.service';\n\ndescribe('AccountsController', () => {\n  let controller: AccountsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AccountsController],\n      providers: [AccountsService],\n    }).compile();\n\n    controller = module.get<AccountsController>(AccountsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/accounts.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { AccountsService } from './accounts.service';\nimport { UpdateAccountDto } from './dto/update-account.dto';\nimport { Prisma } from '@prisma/client';\nimport { TransferAccountDTO } from './dto/transfer-account.dto';\n\n@Controller('accounts')\nexport class AccountsController {\n  constructor(private readonly accountsService: AccountsService) {}\n\n  @Post()\n  create(@Body() createAccountDto: Prisma.AccountCreateInput) {\n    return this.accountsService.create(createAccountDto);\n  }\n\n  @Post('transfer')\n  transfer(@Body() transferAccountDTO: TransferAccountDTO) {\n    return this.accountsService.transfer(transferAccountDTO);\n  }\n\n  @Get()\n  findAll() {\n    return this.accountsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.accountsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateAccountDto: UpdateAccountDto) {\n    return this.accountsService.update(+id, updateAccountDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.accountsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/accounts.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AccountsService } from './accounts.service';\nimport { AccountsController } from './accounts.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [AccountsController],\n  providers: [AccountsService, PrismaService],\n})\nexport class AccountsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/accounts.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AccountsService } from './accounts.service';\n\ndescribe('AccountsService', () => {\n  let service: AccountsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [AccountsService],\n    }).compile();\n\n    service = module.get<AccountsService>(AccountsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/accounts.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateAccountDto } from './dto/create-account.dto';\nimport { UpdateAccountDto } from './dto/update-account.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\nimport { TransferAccountDTO } from './dto/transfer-account.dto';\n\n@Injectable()\nexport class AccountsService {\n  constructor(private prisma: PrismaService) {}\n\n  transfer(transferAccountDTO: TransferAccountDTO) {\n    const { sender: from, receiver: to, amount } = transferAccountDTO;\n    return this.prisma.$transaction(async (tx) => {\n      // John Account\n      // 1. Decrement amount from the sender.\n      const sender = await tx.account.update({\n        data: {\n          balance: {\n            decrement: amount,\n          },\n        },\n        where: {\n          id: from,\n        },\n      });\n\n      // 2. Verify that the sender's balance didn't go below zero.\n      if (sender.balance < 0) {\n        throw new Error(`${from} doesn't have enough to send ${amount}`);\n      }\n\n      // 3. Increment the recipient's balance by amount\n      // SAM Account\n      const recipient = await tx.account.update({\n        data: {\n          balance: {\n            increment: amount,\n          },\n        },\n        where: {\n          id: to,\n        },\n      });\n\n      return recipient;\n    });\n  }\n\n  create(createAccountDto: Prisma.AccountCreateInput) {\n    return this.prisma.account.create({ data: createAccountDto });\n  }\n\n  findAll() {\n    return `This action returns all accounts`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} account`;\n  }\n\n  update(id: number, updateAccountDto: UpdateAccountDto) {\n    return `This action updates a #${id} account`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} account`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/dto/create-account.dto.ts",
    "content": "export class CreateAccountDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/dto/transfer-account.dto.ts",
    "content": "export class TransferAccountDTO {\n  sender: number;\n  receiver: number;\n  amount: number;\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/accounts/dto/update-account.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateAccountDto } from './create-account.dto';\n\nexport class UpdateAccountDto extends PartialType(CreateAccountDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/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": "module-20-prisma-integration/lesson-11-interactive-transactions/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { PrismaService } from './prisma.service';\n\n@Controller()\nexport class AppController {\n  constructor(\n    private readonly appService: AppService,\n    private prisma: PrismaService,\n  ) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Get('sequential')\n  getSequentialResults() {\n    return this.prisma.$transaction([\n      this.prisma.post.findMany(),\n      this.prisma.artist.findMany(),\n      this.prisma.song.findMany(),\n      this.prisma.application.findMany(),\n    ]);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { SongsModule } from './songs/songs.module';\nimport { ArtistsModule } from './artists/artists.module';\nimport { UsersModule } from './users/users.module';\nimport { PostsModule } from './posts/posts.module';\nimport { ApplicationsModule } from './applications/applications.module';\nimport { PrismaService } from './prisma.service';\nimport { AccountsModule } from './accounts/accounts.module';\n\n@Module({\n  imports: [\n    SongsModule,\n    ArtistsModule,\n    UsersModule,\n    PostsModule,\n    ApplicationsModule,\n    AccountsModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService, PrismaService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/applications.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ApplicationsController } from './applications.controller';\nimport { ApplicationsService } from './applications.service';\n\ndescribe('ApplicationsController', () => {\n  let controller: ApplicationsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ApplicationsController],\n      providers: [ApplicationsService],\n    }).compile();\n\n    controller = module.get<ApplicationsController>(ApplicationsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/applications.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ApplicationsService } from './applications.service';\nimport { CreateApplicationDto } from './dto/create-application.dto';\nimport { UpdateApplicationDto } from './dto/update-application.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('applications')\nexport class ApplicationsController {\n  constructor(private readonly applicationsService: ApplicationsService) {}\n\n  @Post()\n  create(@Body() createApplicationDto: Prisma.CustomerCreateInput) {\n    return this.applicationsService.create(createApplicationDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.applicationsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.applicationsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateApplicationDto: UpdateApplicationDto,\n  ) {\n    return this.applicationsService.update(+id, updateApplicationDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.applicationsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/applications.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ApplicationsService } from './applications.service';\nimport { ApplicationsController } from './applications.controller';\n\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ApplicationsController],\n  providers: [ApplicationsService, PrismaService],\n})\nexport class ApplicationsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/applications.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ApplicationsService } from './applications.service';\n\ndescribe('ApplicationsService', () => {\n  let service: ApplicationsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ApplicationsService],\n    }).compile();\n\n    service = module.get<ApplicationsService>(ApplicationsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/applications.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateApplicationDto } from './dto/create-application.dto';\nimport { UpdateApplicationDto } from './dto/update-application.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ApplicationsService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createApplicationDto: Prisma.CustomerCreateInput) {\n    return this.prisma.customer.create({ data: createApplicationDto });\n  }\n\n  findAll() {\n    return `This action returns all applications`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} application`;\n  }\n\n  update(id: number, updateApplicationDto: UpdateApplicationDto) {\n    return `This action updates a #${id} application`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} application`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/dto/create-application.dto.ts",
    "content": "export class CreateApplicationDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/applications/dto/update-application.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateApplicationDto } from './create-application.dto';\n\nexport class UpdateApplicationDto extends PartialType(CreateApplicationDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/artists.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsController } from './artists.controller';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsController', () => {\n  let controller: ArtistsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [ArtistsController],\n      providers: [ArtistsService],\n    }).compile();\n\n    controller = module.get<ArtistsController>(ArtistsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/artists.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('artists')\nexport class ArtistsController {\n  constructor(private readonly artistsService: ArtistsService) {}\n\n  @Post()\n  create(@Body() createArtistDto: Prisma.ArtistCreateInput) {\n    return this.artistsService.create(createArtistDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.artistsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.artistsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateArtistDto: UpdateArtistDto) {\n    return this.artistsService.update(+id, updateArtistDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.artistsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/artists.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ArtistsService } from './artists.service';\nimport { ArtistsController } from './artists.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [ArtistsController],\n  providers: [ArtistsService, PrismaService],\n})\nexport class ArtistsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/artists.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { ArtistsService } from './artists.service';\n\ndescribe('ArtistsService', () => {\n  let service: ArtistsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [ArtistsService],\n    }).compile();\n\n    service = module.get<ArtistsService>(ArtistsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/artists.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateArtistDto } from './dto/create-artist.dto';\nimport { UpdateArtistDto } from './dto/update-artist.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class ArtistsService {\n  constructor(private prisma: PrismaService) {}\n  create(createArtistDto: Prisma.ArtistCreateInput) {\n    return this.prisma.artist.create({\n      data: createArtistDto,\n    });\n  }\n\n  findAll() {\n    return `This action returns all artists`;\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} artist`;\n  }\n\n  update(id: number, updateArtistDto: UpdateArtistDto) {\n    return `This action updates a #${id} artist`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} artist`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/dto/create-artist.dto.ts",
    "content": "export class CreateArtistDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/artists/dto/update-artist.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateArtistDto } from './create-artist.dto';\n\nexport class UpdateArtistDto extends PartialType(CreateArtistDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/dto/create-post.dto.ts",
    "content": "export class CreatePostDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/dto/update-post.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreatePostDto } from './create-post.dto';\n\nexport class UpdatePostDto extends PartialType(CreatePostDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/posts.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { PostsController } from './posts.controller';\nimport { PostsService } from './posts.service';\n\ndescribe('PostsController', () => {\n  let controller: PostsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [PostsController],\n      providers: [PostsService],\n    }).compile();\n\n    controller = module.get<PostsController>(PostsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/posts.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { CreatePostDto } from './dto/create-post.dto';\nimport { UpdatePostDto } from './dto/update-post.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('posts')\nexport class PostsController {\n  constructor(private readonly postsService: PostsService) {}\n\n  @Post()\n  @Post()\n  create(@Body() createPostDto: Prisma.PostCreateInput) {\n    return this.postsService.create(createPostDto);\n  }\n  @Get()\n  findAll(\n    @Body()\n    where: Prisma.PostWhereUniqueInput,\n  ) {\n    return this.postsService.findAll(where);\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.postsService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {\n    return this.postsService.update(+id, updatePostDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.postsService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/posts.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { PostsService } from './posts.service';\nimport { PostsController } from './posts.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [PostsController],\n  providers: [PostsService, PrismaService],\n})\nexport class PostsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/posts.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { PostsService } from './posts.service';\n\ndescribe('PostsService', () => {\n  let service: PostsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [PostsService],\n    }).compile();\n\n    service = module.get<PostsService>(PostsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/posts/posts.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreatePostDto } from './dto/create-post.dto';\nimport { UpdatePostDto } from './dto/update-post.dto';\n\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class PostsService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createPostDto: Prisma.PostCreateInput) {\n    return this.prisma.post.create({ data: createPostDto });\n  }\n\n  findAll(where: Prisma.PostWhereUniqueInput) {\n    return this.prisma.post.findMany({\n      where,\n    });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} post`;\n  }\n\n  update(id: number, updatePostDto: UpdatePostDto) {\n    return `This action updates a #${id} post`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} post`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/prisma.service.ts",
    "content": "import { Injectable, OnModuleInit } from '@nestjs/common';\nimport { PrismaClient } from '@prisma/client';\n\n@Injectable()\nexport class PrismaService extends PrismaClient implements OnModuleInit {\n  onModuleInit() {\n    this.$connect();\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/dto/create-song.dto.ts",
    "content": "export class CreateSongDto {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/dto/update-song.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateSongDto } from './create-song.dto';\n\nexport class UpdateSongDto extends PartialType(CreateSongDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/songs.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsController } from './songs.controller';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsController', () => {\n  let controller: SongsController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [SongsController],\n      providers: [SongsService],\n    }).compile();\n\n    controller = module.get<SongsController>(SongsController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/songs.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  Body,\n  Patch,\n  Param,\n  Delete,\n} from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { Prisma } from '@prisma/client';\n\n@Controller('songs')\nexport class SongsController {\n  constructor(private readonly songsService: SongsService) {}\n\n  @Post()\n  create(@Body() createSongDto: Prisma.SongCreateInput) {\n    return this.songsService.create(createSongDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.songsService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.songsService.findOne({ id: +id });\n  }\n\n  @Patch(':id')\n  update(\n    @Param('id') id: string,\n    @Body() updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.songsService.update({ id: +id }, updateSongDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.songsService.remove({ id: +id });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/songs.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { SongsService } from './songs.service';\nimport { SongsController } from './songs.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [SongsController],\n  providers: [SongsService, PrismaService],\n})\nexport class SongsModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/songs.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { SongsService } from './songs.service';\n\ndescribe('SongsService', () => {\n  let service: SongsService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [SongsService],\n    }).compile();\n\n    service = module.get<SongsService>(SongsService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/songs/songs.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateSongDto } from './dto/create-song.dto';\nimport { UpdateSongDto } from './dto/update-song.dto';\nimport { PrismaService } from '../prisma.service';\nimport { Prisma } from '@prisma/client';\n\n@Injectable()\nexport class SongsService {\n  constructor(private prisma: PrismaService) {}\n  create(createSongDto: Prisma.SongUncheckedCreateInput) {\n    return this.prisma.song.create({\n      data: createSongDto,\n    });\n  }\n\n  findAll() {\n    return this.prisma.song.findMany({ include: { artist: true } });\n  }\n\n  findOne(songWhereUniqueInput: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.findUnique({ where: songWhereUniqueInput });\n  }\n\n  update(\n    where: Prisma.SongWhereUniqueInput,\n    updateSongDto: Prisma.SongUpdateInput,\n  ) {\n    return this.prisma.song.update({\n      where,\n      data: updateSongDto,\n    });\n  }\n\n  remove(where: Prisma.SongWhereUniqueInput) {\n    return this.prisma.song.delete({ where });\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/dto/create-user.dto.ts",
    "content": "export class CreateUserDto {\n  name: string;\n  photo: string;\n  phone: string;\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/dto/update-user.dto.ts",
    "content": "import { PartialType } from '@nestjs/mapped-types';\nimport { CreateUserDto } from './create-user.dto';\n\nexport class UpdateUserDto extends PartialType(CreateUserDto) {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/users.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersController } from './users.controller';\nimport { UsersService } from './users.service';\n\ndescribe('UsersController', () => {\n  let controller: UsersController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [UsersController],\n      providers: [UsersService],\n    }).compile();\n\n    controller = module.get<UsersController>(UsersController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/users.controller.ts",
    "content": "import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\n@Controller('users')\nexport class UsersController {\n  constructor(private readonly usersService: UsersService) {}\n\n  @Post()\n  create(@Body() createUserDto: CreateUserDto) {\n    return this.usersService.create(createUserDto);\n  }\n\n  @Get()\n  findAll() {\n    return this.usersService.findAll();\n  }\n\n  @Get(':id')\n  findOne(@Param('id') id: string) {\n    return this.usersService.findOne(+id);\n  }\n\n  @Patch(':id')\n  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {\n    return this.usersService.update(+id, updateUserDto);\n  }\n\n  @Delete(':id')\n  remove(@Param('id') id: string) {\n    return this.usersService.remove(+id);\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/users.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { UsersService } from './users.service';\nimport { UsersController } from './users.controller';\nimport { PrismaService } from '../prisma.service';\n\n@Module({\n  controllers: [UsersController],\n  providers: [UsersService, PrismaService],\n})\nexport class UsersModule {}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/users.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\n\ndescribe('UsersService', () => {\n  let service: UsersService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [UsersService],\n    }).compile();\n\n    service = module.get<UsersService>(UsersService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/src/users/users.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { CreateUserDto } from './dto/create-user.dto';\nimport { UpdateUserDto } from './dto/update-user.dto';\n\nimport { PrismaService } from '../prisma.service';\n\n@Injectable()\nexport class UsersService {\n  constructor(private prisma: PrismaService) {}\n\n  create(createUserDto: CreateUserDto) {\n    return this.prisma.user.create({\n      data: {\n        name: createUserDto.name,\n        profile: {\n          create: {\n            phone: createUserDto.phone,\n            photo: createUserDto.photo,\n          },\n        },\n      },\n    });\n  }\n\n  findAll() {\n    return this.prisma.user.findMany({ include: { profile: true } });\n  }\n\n  findOne(id: number) {\n    return `This action returns a #${id} user`;\n  }\n\n  update(id: number, updateUserDto: UpdateUserDto) {\n    return `This action updates a #${id} user`;\n  }\n\n  remove(id: number) {\n    return `This action removes a #${id} user`;\n  }\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/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": "module-20-prisma-integration/lesson-11-interactive-transactions/test/song/song.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from '../song/../../src/app.module';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { Song } from '../song/../../src/song/song.entity';\nimport { SongModule } from '../song/../../src/song/song.module';\nimport { CreateSongDTO } from '../song/../../src/song/dto/create-song-dto';\n\ndescribe('Song Resolver (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  beforeAll(async () => {\n    const moduleRef = await Test.createTestingModule({\n      imports: [\n        TypeOrmModule.forRoot({\n          type: 'postgres',\n          url: 'postgres://postgres:root@localhost:5432/test-dev',\n          synchronize: true,\n          entities: [Song],\n          dropSchema: true,\n        }),\n        SongModule,\n      ],\n    }).compile();\n\n    app = moduleRef.createNestApplication();\n    await app.init();\n  });\n\n  afterEach(async () => {\n    // Fetch all the entities\n    const songRepository = app.get('SongRepository');\n    await songRepository.clear();\n  });\n\n  afterAll(async () => {\n    await app.close();\n  });\n\n  const createSong = (createSongDTO: CreateSongDTO): Promise<Song> => {\n    const song = new Song();\n    song.title = createSongDTO.title;\n    const songRepo = app.get('SongRepository');\n    return songRepo.save(song);\n  };\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n\n  it('(Query) it should get all songs with songs query', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query {\n        songs {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData);\n\n    expect(results.statusCode).toBe(200);\n    expect(results.body).toEqual({ data: { songs: [newSong] } });\n  });\n\n  it('(Query) it should get a song by id', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `query GetSong($id: ID!){\n        song(id: $id){\n          title\n          id\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body).toEqual({ data: { song: newSong } });\n  });\n\n  it('(Mutation) it should create a new song', async () => {\n    const queryData = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.createSong.title).toBe('Animals');\n  });\n\n  it('(Mutation) it should update existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation UpdateSong($id: ID!, $updateSongInput: UpdateSongInput!){\n        updateSong(id: $id, updateSongInput: $updateSongInput){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n        updateSongInput: {\n          title: 'Lover',\n        },\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.updateSong.affected).toBe(1);\n  });\n\n  it('(Mutation) it should delete existing song', async () => {\n    const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `mutation DeleteSong($id: ID!){\n        deleteSong(id: $id){\n          affected\n        }\n      }`,\n      variables: {\n        id: newSong.id,\n      },\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    expect(results.body.data.deleteSong.affected).toBe(1);\n  });\n\n  it('(Subscription) it should test subscription', async () => {\n    // const newSong = await createSong({ title: 'Animals' });\n    const queryData = {\n      query: `subscription SongCreated{\n        songCreated {\n          id\n          title\n        }\n      }`,\n    };\n    const results = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData)\n      .expect(200);\n\n    // console.log(results);\n\n    const queryData1 = {\n      query: `mutation CreateSong($createSongInput: CreateSongInput!){\n        createSong(createSongInput: $createSongInput){\n          title\n          id\n        }\n      }`,\n      variables: {\n        createSongInput: {\n          title: 'Animals',\n        },\n      },\n    };\n    const results1 = await request(app.getHttpServer())\n      .post('/graphql')\n      .send(queryData1)\n      .expect(200);\n\n    console.log(results.body);\n  });\n});\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-20-prisma-integration/lesson-11-interactive-transactions/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/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": "module-21-nestjs-advanced-concepts/0-starter/src/app.controller.ts",
    "content": "import { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/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": "module-21-nestjs-advanced-concepts/0-starter/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/0-starter/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@types/multer\": \"^1.4.7\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/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": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n} from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/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": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-01-file-upload/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@types/multer\": \"^1.4.7\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/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": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n} from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/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": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-02-custom-decorator/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/schedule\": \"^3.0.2\",\n    \"@types/multer\": \"^1.4.7\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/cron\": \"^2.4.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/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": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n} from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ScheduleModule } from '@nestjs/schedule';\nimport { TaskService } from './task/task.service';\n\n@Module({\n  imports: [ScheduleModule.forRoot()],\n  controllers: [AppController],\n  providers: [AppService, TaskService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/task/task.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TaskService } from './task.service';\n\ndescribe('TaskService', () => {\n  let service: TaskService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TaskService],\n    }).compile();\n\n    service = module.get<TaskService>(TaskService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/task/task.service.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\n\n@Injectable()\nexport class TaskService {\n  private readonly logger = new Logger(TaskService.name);\n\n  @Cron('0 * * * * *')\n  myCronTask() {\n    this.logger.debug('Cron Task Called');\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/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": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-03-Task-scheduling/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1\n\n### TEST COOKIE PARSER\nGET http://localhost:3000/set-cookie\n\n### GET COOKIE\nGET  http://localhost:3000/get-cookie"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/schedule\": \"^3.0.2\",\n    \"@types/multer\": \"^1.4.7\",\n    \"cookie-parser\": \"^1.4.6\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/cookie-parser\": \"^1.4.3\",\n    \"@types/cron\": \"^2.4.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/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": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n  Req,\n  Res,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n\n  @Get('get-cookie')\n  finndAll(@Req() req: Request) {\n    console.log(req.cookies);\n    return req.cookies;\n  }\n\n  @Get('set-cookie')\n  setCookie(\n    @Res({ passthrough: true })\n    response: Response,\n  ) {\n    response.cookie(\n      'userId',\n      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',\n    );\n    response.send('Cookie Saved Successfully');\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ScheduleModule } from '@nestjs/schedule';\nimport { TaskService } from './task/task.service';\n\n@Module({\n  imports: [ScheduleModule.forRoot()],\n  controllers: [AppController],\n  providers: [AppService, TaskService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport * as cookieParser from 'cookie-parser';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.use(cookieParser());\n\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/task/task.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TaskService } from './task.service';\n\ndescribe('TaskService', () => {\n  let service: TaskService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TaskService],\n    }).compile();\n\n    service = module.get<TaskService>(TaskService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/task/task.service.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\n\n@Injectable()\nexport class TaskService {\n  private readonly logger = new Logger(TaskService.name);\n\n  //   @Cron('0 * * * * *')\n  //   myCronTask() {\n  //     this.logger.debug('Cron Task Called');\n  //   }\n  // }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/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": "module-21-nestjs-advanced-concepts/lesson-04-cookies/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-04-cookies/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1\n\n### TEST COOKIE PARSER\nGET http://localhost:3000/set-cookie\n\n### GET COOKIE\nGET  http://localhost:3000/get-cookie"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/schedule\": \"^3.0.2\",\n    \"@types/multer\": \"^1.4.7\",\n    \"cookie-parser\": \"^1.4.6\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/cookie-parser\": \"^1.4.3\",\n    \"@types/cron\": \"^2.4.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/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": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n  Req,\n  Res,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n\n  @Get('get-cookie')\n  finndAll(@Req() req: Request) {\n    console.log(req.cookies);\n    return req.cookies;\n  }\n\n  @Get('set-cookie')\n  setCookie(\n    @Res({ passthrough: true })\n    response: Response,\n  ) {\n    response.cookie(\n      'userId',\n      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',\n    );\n    response.send('Cookie Saved Successfully');\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ScheduleModule } from '@nestjs/schedule';\nimport { TaskService } from './task/task.service';\n\n@Module({\n  imports: [ScheduleModule.forRoot()],\n  controllers: [AppController],\n  providers: [AppService, TaskService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport * as cookieParser from 'cookie-parser';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.use(cookieParser());\n\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/task/task.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TaskService } from './task.service';\n\ndescribe('TaskService', () => {\n  let service: TaskService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TaskService],\n    }).compile();\n\n    service = module.get<TaskService>(TaskService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/task/task.service.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\n\n@Injectable()\nexport class TaskService {\n  private readonly logger = new Logger(TaskService.name);\n\n  //   @Cron('0 * * * * *')\n  //   myCronTask() {\n  //     this.logger.debug('Cron Task Called');\n  //   }\n  // }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/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": "module-21-nestjs-advanced-concepts/lesson-05-queues/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-05-queues/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/docker-compose.yml",
    "content": "version: '3'\nservices:\n  redis:\n    image: redis:alpine\n    ports:\n      - 6379:6379\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1\n\n### TEST COOKIE PARSER\nGET http://localhost:3000/set-cookie\n\n### GET COOKIE\nGET  http://localhost:3000/get-cookie\n\n### CONVERT .WAV FILE TO Mp3\nPOST http://localhost:3000/audio/convert"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/bull\": \"^10.0.1\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/event-emitter\": \"^2.0.1\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/schedule\": \"^3.0.2\",\n    \"@types/multer\": \"^1.4.7\",\n    \"bull\": \"^4.11.3\",\n    \"cookie-parser\": \"^1.4.6\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/cookie-parser\": \"^1.4.3\",\n    \"@types/cron\": \"^2.4.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/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": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n  Req,\n  Res,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n\n  @Get('get-cookie')\n  finndAll(@Req() req: Request) {\n    console.log(req.cookies);\n    return req.cookies;\n  }\n\n  @Get('set-cookie')\n  setCookie(\n    @Res({ passthrough: true })\n    response: Response,\n  ) {\n    response.cookie(\n      'userId',\n      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',\n    );\n    response.send('Cookie Saved Successfully');\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ScheduleModule } from '@nestjs/schedule';\nimport { TaskService } from './task/task.service';\nimport { AudioModule } from './audio/audio.module';\nimport { BullModule } from '@nestjs/bull';\nimport { EventEmitterModule } from '@nestjs/event-emitter';\n\n@Module({\n  imports: [\n    ScheduleModule.forRoot(),\n    BullModule.forRoot({\n      redis: {\n        host: 'localhost',\n        port: 6379,\n      },\n    }),\n    EventEmitterModule.forRoot(),\n    AudioModule,\n  ],\n  controllers: [AppController],\n  providers: [AppService, TaskService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/audio/audio-converted-listener.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { OnEvent } from '@nestjs/event-emitter';\nimport { AudioConvertedEvent } from './events/audio-converted-event';\n\n@Injectable()\nexport class AudioConvertedListener {\n  @OnEvent('audio.converted')\n  handleAudioConvertedEvent(event: AudioConvertedEvent) {\n    console.log(event);\n    console.log(\n      'Notification has sent to user that file is converted successfully',\n    );\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/audio/audio.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AudioController } from './audio.controller';\n\ndescribe('AudioController', () => {\n  let controller: AudioController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AudioController],\n    }).compile();\n\n    controller = module.get<AudioController>(AudioController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/audio/audio.controller.ts",
    "content": "import { InjectQueue } from '@nestjs/bull';\nimport { Controller, Post } from '@nestjs/common';\nimport { Queue } from 'bull';\n\n@Controller('audio')\nexport class AudioController {\n  constructor(\n    @InjectQueue('audio-queue')\n    private readonly audioQueue: Queue,\n  ) {}\n\n  /**\n   * Let's imagine we would like to convert .wav file into .mp3\n   */\n  @Post('convert')\n  async convert() {\n    await this.audioQueue.add('convert', {\n      file: 'sample.wav',\n      id: 1,\n    });\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/audio/audio.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AudioController } from './audio.controller';\nimport { BullModule } from '@nestjs/bull';\nimport { AudioProcessor } from './audio.processor';\nimport { AudioConvertedListener } from './audio-converted-listener';\n\n@Module({\n  imports: [\n    BullModule.registerQueue({\n      name: 'audio-queue',\n    }),\n  ],\n  controllers: [AudioController],\n  providers: [AudioProcessor, AudioConvertedListener],\n})\nexport class AudioModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/audio/audio.processor.ts",
    "content": "import { Process, Processor } from '@nestjs/bull';\nimport { Logger } from '@nestjs/common';\nimport { Job } from 'bull';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\n\n@Processor('audio-queue')\nexport class AudioProcessor {\n  constructor(private eventEmitter: EventEmitter2) {}\n  private logger = new Logger(AudioProcessor.name);\n\n  @Process('convert')\n  handleConvert(job: Job) {\n    this.logger.debug('start converting wav file to mp3');\n    this.logger.debug(job.data);\n    this.logger.debug('file converted successfully');\n    this.eventEmitter.emit('audio.converted', job.data);\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/audio/events/audio-converted-event.ts",
    "content": "export class AudioConvertedEvent {\n  file: string;\n  id: number;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport * as cookieParser from 'cookie-parser';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.use(cookieParser());\n\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/task/task.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TaskService } from './task.service';\n\ndescribe('TaskService', () => {\n  let service: TaskService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TaskService],\n    }).compile();\n\n    service = module.get<TaskService>(TaskService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/task/task.service.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\n\n@Injectable()\nexport class TaskService {\n  private readonly logger = new Logger(TaskService.name);\n\n  //   @Cron('0 * * * * *')\n  //   myCronTask() {\n  //     this.logger.debug('Cron Task Called');\n  //   }\n  // }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/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": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-06-event-emitter/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/docker-compose.yml",
    "content": "version: '3'\nservices:\n  redis:\n    image: redis:alpine\n    ports:\n      - 6379:6379\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1\n\n### TEST COOKIE PARSER\nGET http://localhost:3000/set-cookie\n\n### GET COOKIE\nGET  http://localhost:3000/get-cookie\n\n### CONVERT .WAV FILE TO Mp3\nPOST http://localhost:3000/audio/convert"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/bull\": \"^10.0.1\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/event-emitter\": \"^2.0.1\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/schedule\": \"^3.0.2\",\n    \"@types/multer\": \"^1.4.7\",\n    \"bull\": \"^4.11.3\",\n    \"cookie-parser\": \"^1.4.6\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/cookie-parser\": \"^1.4.3\",\n    \"@types/cron\": \"^2.4.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/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": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n  Req,\n  Res,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n\n  @Get('get-cookie')\n  finndAll(@Req() req: Request) {\n    console.log(req.cookies);\n    return req.cookies;\n  }\n\n  @Get('set-cookie')\n  setCookie(\n    @Res({ passthrough: true })\n    response: Response,\n  ) {\n    response.cookie(\n      'userId',\n      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',\n    );\n    response.send('Cookie Saved Successfully');\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ScheduleModule } from '@nestjs/schedule';\nimport { TaskService } from './task/task.service';\nimport { AudioModule } from './audio/audio.module';\nimport { BullModule } from '@nestjs/bull';\nimport { EventEmitterModule } from '@nestjs/event-emitter';\nimport { FileController } from './file/file.controller';\n\n@Module({\n  imports: [\n    ScheduleModule.forRoot(),\n    EventEmitterModule.forRoot(),\n    BullModule.forRoot({\n      redis: {\n        host: 'localhost',\n        port: 6379,\n      },\n    }),\n    AudioModule,\n  ],\n  controllers: [AppController, FileController],\n  providers: [AppService, TaskService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/audio/audio-converted-listener.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { OnEvent } from '@nestjs/event-emitter';\nimport { AudioConvertedEvent } from './events/audio-converted-event';\n\n@Injectable()\nexport class AudioConvertedListener {\n  @OnEvent('audio.converted') // We have registered a new event lister with audio.converted name\n  handleAudioConvertedEvent(event: AudioConvertedEvent) {\n    //We have to create the type for the AudioConvertedEvent\n    console.log(event);\n    // Here you can have your EmailService method you can call here\n    console.log(\n      'Notification has sent to user that file is converted successfully',\n    );\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/audio/audio.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AudioController } from './audio.controller';\n\ndescribe('AudioController', () => {\n  let controller: AudioController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AudioController],\n    }).compile();\n\n    controller = module.get<AudioController>(AudioController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/audio/audio.controller.ts",
    "content": "import { InjectQueue } from '@nestjs/bull';\nimport { Controller, Post } from '@nestjs/common';\nimport { Queue } from 'bull';\n\n@Controller('audio')\nexport class AudioController {\n  constructor(\n    @InjectQueue('audio-queue')\n    private readonly audioQueue: Queue,\n  ) {}\n\n  /**\n   * Let's imagine we would like to convert .wav file into .mp3\n   */\n  @Post('convert')\n  async convert() {\n    await this.audioQueue.add('convert', {\n      file: 'sample.wav',\n      id: 1,\n    });\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/audio/audio.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AudioController } from './audio.controller';\nimport { BullModule } from '@nestjs/bull';\nimport { AudioProcessor } from './audio.processor';\nimport { AudioConvertedListener } from './audio-converted-listener';\n\n@Module({\n  imports: [\n    BullModule.registerQueue({\n      name: 'audio-queue',\n    }),\n  ],\n  controllers: [AudioController],\n  providers: [AudioProcessor, AudioConvertedListener],\n})\nexport class AudioModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/audio/audio.processor.ts",
    "content": "import { Process, Processor } from '@nestjs/bull';\nimport { Logger } from '@nestjs/common';\nimport { Job } from 'bull';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\n\n@Processor('audio-queue')\nexport class AudioProcessor {\n  constructor(private eventEmitter: EventEmitter2) {}\n  private logger = new Logger(AudioProcessor.name);\n\n  @Process('convert')\n  handleConvert(job: Job) {\n    this.logger.debug('start converting wav file to mp3');\n    this.logger.debug(job.data);\n    this.logger.debug('file converted successfully');\n    this.eventEmitter.emit('audio.converted', job.data);\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/audio/events/audio-converted-event.ts",
    "content": "export class AudioConvertedEvent {\n  file: string;\n  id: number;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/file/file.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { FileController } from './file.controller';\n\ndescribe('FileController', () => {\n  let controller: FileController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [FileController],\n    }).compile();\n\n    controller = module.get<FileController>(FileController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/file/file.controller.ts",
    "content": "import { Controller, Get, Header, Res, StreamableFile } from '@nestjs/common';\nimport { Response } from 'express';\nimport { createReadStream } from 'fs';\nimport { join } from 'path';\n\n@Controller('file')\nexport class FileController {\n  @Get('stream-file')\n  getFile1(): StreamableFile {\n    const file = createReadStream(join(process.cwd(), 'package.json'));\n    return new StreamableFile(file);\n  }\n  @Get('stream-file-customize')\n  getFileCustomizedResponse(@Res({ passthrough: true }) res): StreamableFile {\n    const file = createReadStream(join(process.cwd(), 'package.json'));\n    res.set({\n      'Content-Type': 'application/json',\n      'Content-Disposition': 'attachment; filename=\"package.json',\n    });\n    return new StreamableFile(file);\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport * as cookieParser from 'cookie-parser';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.use(cookieParser());\n\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/task/task.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TaskService } from './task.service';\n\ndescribe('TaskService', () => {\n  let service: TaskService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TaskService],\n    }).compile();\n\n    service = module.get<TaskService>(TaskService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/task/task.service.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\n\n@Injectable()\nexport class TaskService {\n  private readonly logger = new Logger(TaskService.name);\n\n  //   @Cron('0 * * * * *')\n  //   myCronTask() {\n  //     this.logger.debug('Cron Task Called');\n  //   }\n  // }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/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": "module-21-nestjs-advanced-concepts/lesson-07-streaming/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-07-streaming/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir: __dirname,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-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"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/README.md",
    "content": "<p align=\"center\">\n  <a href=\"http://nestjs.com/\" target=\"blank\"><img src=\"https://nestjs.com/img/logo-small.svg\" width=\"200\" alt=\"Nest Logo\" /></a>\n</p>\n\n[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456\n[circleci-url]: https://circleci.com/gh/nestjs/nest\n\n  <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"_blank\">Node.js</a> framework for building efficient and scalable server-side applications.</p>\n    <p align=\"center\">\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/v/@nestjs/core.svg\" alt=\"NPM Version\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/l/@nestjs/core.svg\" alt=\"Package License\" /></a>\n<a href=\"https://www.npmjs.com/~nestjscore\" target=\"_blank\"><img src=\"https://img.shields.io/npm/dm/@nestjs/common.svg\" alt=\"NPM Downloads\" /></a>\n<a href=\"https://circleci.com/gh/nestjs/nest\" target=\"_blank\"><img src=\"https://img.shields.io/circleci/build/github/nestjs/nest/master\" alt=\"CircleCI\" /></a>\n<a href=\"https://coveralls.io/github/nestjs/nest?branch=master\" target=\"_blank\"><img src=\"https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9\" alt=\"Coverage\" /></a>\n<a href=\"https://discord.gg/G7Qnnhy\" target=\"_blank\"><img src=\"https://img.shields.io/badge/discord-online-brightgreen.svg\" alt=\"Discord\"/></a>\n<a href=\"https://opencollective.com/nest#backer\" target=\"_blank\"><img src=\"https://opencollective.com/nest/backers/badge.svg\" alt=\"Backers on Open Collective\" /></a>\n<a href=\"https://opencollective.com/nest#sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/nest/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" /></a>\n  <a href=\"https://paypal.me/kamilmysliwiec\" target=\"_blank\"><img src=\"https://img.shields.io/badge/Donate-PayPal-ff3f59.svg\"/></a>\n    <a href=\"https://opencollective.com/nest#sponsor\"  target=\"_blank\"><img src=\"https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg\" alt=\"Support us\"></a>\n  <a href=\"https://twitter.com/nestframework\" target=\"_blank\"><img src=\"https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow\"></a>\n</p>\n  <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)\n  [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->\n\n## Description\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n## Support\n\nNest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).\n\n## Stay in touch\n\n- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)\n- Website - [https://nestjs.com](https://nestjs.com/)\n- Twitter - [@nestframework](https://twitter.com/nestframework)\n\n## License\n\nNest is [MIT licensed](LICENSE).\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/docker-compose.yml",
    "content": "version: '3'\nservices:\n  redis:\n    image: redis:alpine\n    ports:\n      - 6379:6379\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/http-client.http",
    "content": "### FIND USER ON THE BASED ON ID\nGET http://localhost:3000/user/1\n\n### TEST COOKIE PARSER\nGET http://localhost:3000/set-cookie\n\n### GET COOKIE\nGET  http://localhost:3000/get-cookie\n\n### CONVERT .WAV FILE TO Mp3\nPOST http://localhost:3000/audio/convert\n\n### TEST SESSION\n\nGET http://localhost:3000/login\n\n### USER PROFILE\nGET http://localhost:3000/profile"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\",\n  \"compilerOptions\": {\n    \"deleteOutDir\": true\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/package.json",
    "content": "{\n  \"name\": \"fie-upload\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\",\n    \"test\": \"jest\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"jest --config ./test/jest-e2e.json\"\n  },\n  \"dependencies\": {\n    \"@nestjs/bull\": \"^10.0.1\",\n    \"@nestjs/common\": \"^10.0.0\",\n    \"@nestjs/core\": \"^10.0.0\",\n    \"@nestjs/event-emitter\": \"^2.0.1\",\n    \"@nestjs/platform-express\": \"^10.0.0\",\n    \"@nestjs/schedule\": \"^3.0.2\",\n    \"@types/multer\": \"^1.4.7\",\n    \"bull\": \"^4.11.3\",\n    \"cookie-parser\": \"^1.4.6\",\n    \"express-session\": \"^1.17.3\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.8.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^10.0.0\",\n    \"@nestjs/schematics\": \"^10.0.0\",\n    \"@nestjs/testing\": \"^10.0.0\",\n    \"@types/cookie-parser\": \"^1.4.3\",\n    \"@types/cron\": \"^2.4.0\",\n    \"@types/express\": \"^4.17.17\",\n    \"@types/express-session\": \"^1.17.7\",\n    \"@types/jest\": \"^29.5.2\",\n    \"@types/node\": \"^20.3.1\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.11\",\n    \"@typescript-eslint/parser\": \"^5.59.11\",\n    \"eslint\": \"^8.42.0\",\n    \"eslint-config-prettier\": \"^8.8.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"^29.5.0\",\n    \"prettier\": \"^2.8.8\",\n    \"source-map-support\": \"^0.5.21\",\n    \"supertest\": \"^6.3.3\",\n    \"ts-jest\": \"^29.1.0\",\n    \"ts-loader\": \"^9.4.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"typescript\": \"^5.1.3\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/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": "module-21-nestjs-advanced-concepts/lesson-08-session/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Post,\n  HttpStatus,\n  ParseFilePipeBuilder,\n  UploadedFile,\n  UseInterceptors,\n  Req,\n  Res,\n  Session,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport { AppService } from './app.service';\nimport { FileInterceptor } from '@nestjs/platform-express';\nimport { diskStorage } from 'multer';\nimport { User } from './user.decorator';\nimport { UserEntity } from './user.entity';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  getHello(): string {\n    return this.appService.getHello();\n  }\n\n  @Post('upload')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadFile(@UploadedFile() file: Express.Multer.File) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  // only want to accept png file\n  @Post('upload-png')\n  @UseInterceptors(\n    FileInterceptor('file', {\n      storage: diskStorage({\n        destination: './upload/files',\n        filename: (req, file, cb) => {\n          cb(null, file.originalname);\n        },\n      }),\n    }),\n  )\n  uploadPngFile(\n    @UploadedFile(\n      new ParseFilePipeBuilder()\n        .addFileTypeValidator({\n          fileType: 'png',\n        })\n        // .addMaxSizeValidator({\n        //   maxSize: 70706,\n        // })\n        .build({\n          errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,\n        }),\n    )\n    file: Express.Multer.File,\n  ) {\n    console.log(file);\n    return {\n      messge: 'file uploaded successfully!',\n    };\n  }\n\n  @Get('/user/:id')\n  findOne(\n    @User()\n    user: UserEntity,\n  ) {\n    console.log(user);\n    return user;\n  }\n\n  @Get('get-cookie')\n  finndAll(@Req() req: Request) {\n    console.log(req.cookies);\n    return req.cookies;\n  }\n\n  @Get('set-cookie')\n  setCookie(\n    @Res({ passthrough: true })\n    response: Response,\n  ) {\n    response.cookie(\n      'userId',\n      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',\n    );\n    response.send('Cookie Saved Successfully');\n  }\n\n  @Get('login')\n  loginUser(@Session() session: Record<string, any>) {\n    session.user = { id: 1, username: 'Jane' };\n    return 'LoggedIn';\n  }\n\n  @Get('profile')\n  profile(@Session() session: Record<string, any>) {\n    const user = session.user;\n    if (user) {\n      return `Hello, ${user.username}`;\n    } else {\n      return 'Not logged in';\n    }\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { ScheduleModule } from '@nestjs/schedule';\nimport { TaskService } from './task/task.service';\nimport { AudioModule } from './audio/audio.module';\nimport { BullModule } from '@nestjs/bull';\nimport { EventEmitterModule } from '@nestjs/event-emitter';\nimport { FileController } from './file/file.controller';\n\n@Module({\n  imports: [\n    ScheduleModule.forRoot(),\n    EventEmitterModule.forRoot(),\n    BullModule.forRoot({\n      redis: {\n        host: 'localhost',\n        port: 6379,\n      },\n    }),\n    AudioModule,\n  ],\n  controllers: [AppController, FileController],\n  providers: [AppService, TaskService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return 'Hello World!';\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/audio/audio-converted-listener.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { OnEvent } from '@nestjs/event-emitter';\nimport { AudioConvertedEvent } from './events/audio-converted-event';\n\n@Injectable()\nexport class AudioConvertedListener {\n  @OnEvent('audio.converted') // We have registered a new event lister with audio.converted name\n  handleAudioConvertedEvent(event: AudioConvertedEvent) {\n    //We have to create the type for the AudioConvertedEvent\n    console.log(event);\n    // Here you can have your EmailService method you can call here\n    console.log(\n      'Notification has sent to user that file is converted successfully',\n    );\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/audio/audio.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { AudioController } from './audio.controller';\n\ndescribe('AudioController', () => {\n  let controller: AudioController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [AudioController],\n    }).compile();\n\n    controller = module.get<AudioController>(AudioController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/audio/audio.controller.ts",
    "content": "import { InjectQueue } from '@nestjs/bull';\nimport { Controller, Post } from '@nestjs/common';\nimport { Queue } from 'bull';\n\n@Controller('audio')\nexport class AudioController {\n  constructor(\n    @InjectQueue('audio-queue')\n    private readonly audioQueue: Queue,\n  ) {}\n\n  /**\n   * Let's imagine we would like to convert .wav file into .mp3\n   */\n  @Post('convert')\n  async convert() {\n    await this.audioQueue.add('convert', {\n      file: 'sample.wav',\n      id: 1,\n    });\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/audio/audio.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AudioController } from './audio.controller';\nimport { BullModule } from '@nestjs/bull';\nimport { AudioProcessor } from './audio.processor';\nimport { AudioConvertedListener } from './audio-converted-listener';\n\n@Module({\n  imports: [\n    BullModule.registerQueue({\n      name: 'audio-queue',\n    }),\n  ],\n  controllers: [AudioController],\n  providers: [AudioProcessor, AudioConvertedListener],\n})\nexport class AudioModule {}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/audio/audio.processor.ts",
    "content": "import { Process, Processor } from '@nestjs/bull';\nimport { Logger } from '@nestjs/common';\nimport { Job } from 'bull';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\n\n@Processor('audio-queue')\nexport class AudioProcessor {\n  constructor(private eventEmitter: EventEmitter2) {}\n  private logger = new Logger(AudioProcessor.name);\n\n  @Process('convert')\n  handleConvert(job: Job) {\n    this.logger.debug('start converting wav file to mp3');\n    this.logger.debug(job.data);\n    this.logger.debug('file converted successfully');\n    this.eventEmitter.emit('audio.converted', job.data);\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/audio/events/audio-converted-event.ts",
    "content": "export class AudioConvertedEvent {\n  file: string;\n  id: number;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/file/file.controller.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { FileController } from './file.controller';\n\ndescribe('FileController', () => {\n  let controller: FileController;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      controllers: [FileController],\n    }).compile();\n\n    controller = module.get<FileController>(FileController);\n  });\n\n  it('should be defined', () => {\n    expect(controller).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/file/file.controller.ts",
    "content": "import { Controller, Get, Header, Res, StreamableFile } from '@nestjs/common';\nimport { Response } from 'express';\nimport { createReadStream } from 'fs';\nimport { join } from 'path';\n\n@Controller('file')\nexport class FileController {\n  @Get('stream-file')\n  getFile1(): StreamableFile {\n    const file = createReadStream(join(process.cwd(), 'package.json'));\n    return new StreamableFile(file);\n  }\n  @Get('stream-file-customize')\n  getFileCustomizedResponse(@Res({ passthrough: true }) res): StreamableFile {\n    const file = createReadStream(join(process.cwd(), 'package.json'));\n    res.set({\n      'Content-Type': 'application/json',\n      'Content-Disposition': 'attachment; filename=\"package.json',\n    });\n    return new StreamableFile(file);\n  }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport * as cookieParser from 'cookie-parser';\nimport * as session from 'express-session';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.use(cookieParser());\n\n  app.use(\n    session({\n      secret: 'my-secret',\n      resave: false,\n      saveUninitialized: false,\n    }),\n  );\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/task/task.service.spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { TaskService } from './task.service';\n\ndescribe('TaskService', () => {\n  let service: TaskService;\n\n  beforeEach(async () => {\n    const module: TestingModule = await Test.createTestingModule({\n      providers: [TaskService],\n    }).compile();\n\n    service = module.get<TaskService>(TaskService);\n  });\n\n  it('should be defined', () => {\n    expect(service).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/task/task.service.ts",
    "content": "import { Injectable, Logger } from '@nestjs/common';\nimport { Cron } from '@nestjs/schedule';\n\n@Injectable()\nexport class TaskService {\n  private readonly logger = new Logger(TaskService.name);\n\n  //   @Cron('0 * * * * *')\n  //   myCronTask() {\n  //     this.logger.debug('Cron Task Called');\n  //   }\n  // }\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/user.decorator.ts",
    "content": "import { ExecutionContext, createParamDecorator } from '@nestjs/common';\n\nexport const User = createParamDecorator(\n  (data: unknown, ctx: ExecutionContext) => {\n    const request = ctx.switchToHttp().getRequest();\n    request.user = { id: 1, name: 'Jane Done' };\n    return request.user;\n  },\n);\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/src/user.entity.ts",
    "content": "export class UserEntity {\n  id: number;\n  name: string;\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/test/app.e2e-spec.ts",
    "content": "import { Test, TestingModule } from '@nestjs/testing';\nimport { INestApplication } from '@nestjs/common';\nimport * as request from 'supertest';\nimport { AppModule } from './../src/app.module';\n\ndescribe('AppController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeEach(async () => {\n    const moduleFixture: TestingModule = await Test.createTestingModule({\n      imports: [AppModule],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('/ (GET)', () => {\n    return request(app.getHttpServer())\n      .get('/')\n      .expect(200)\n      .expect('Hello World!');\n  });\n});\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/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": "module-21-nestjs-advanced-concepts/lesson-08-session/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "module-21-nestjs-advanced-concepts/lesson-08-session/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"ES2021\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  }
]