Full Code of onwuvic/nest-blog-api for AI

master ffda9a4ac9ce cached
43 files
25.3 KB
7.3k tokens
68 symbols
1 requests
Download .txt
Repository: onwuvic/nest-blog-api
Branch: master
Commit: ffda9a4ac9ce
Files: 43
Total size: 25.3 KB

Directory structure:
gitextract_35nzldb_/

├── .gitignore
├── .prettierrc
├── README.md
├── nest-cli.json
├── package.json
├── src/
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── core/
│   │   ├── constants/
│   │   │   └── index.ts
│   │   ├── database/
│   │   │   ├── database.config.ts
│   │   │   ├── database.module.ts
│   │   │   ├── database.providers.ts
│   │   │   └── interfaces/
│   │   │       └── dbConfig.interface.ts
│   │   ├── guards/
│   │   │   └── doesUserExist.guard.ts
│   │   └── pipes/
│   │       └── validate.pipe.ts
│   ├── main.ts
│   └── modules/
│       ├── auth/
│       │   ├── auth.controller.spec.ts
│       │   ├── auth.controller.ts
│       │   ├── auth.module.ts
│       │   ├── auth.service.spec.ts
│       │   ├── auth.service.ts
│       │   ├── jwt.strategy.ts
│       │   └── local.strategy.ts
│       ├── posts/
│       │   ├── dto/
│       │   │   └── post.dto.ts
│       │   ├── post.entity.ts
│       │   ├── posts.controller.spec.ts
│       │   ├── posts.controller.ts
│       │   ├── posts.module.ts
│       │   ├── posts.providers.ts
│       │   ├── posts.service.spec.ts
│       │   └── posts.service.ts
│       └── users/
│           ├── dto/
│           │   └── user.dto.ts
│           ├── user.entity.ts
│           ├── users.module.ts
│           ├── users.providers.ts
│           ├── users.service.spec.ts
│           └── users.service.ts
├── test/
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
├── tsconfig.json
└── tslint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# compiled output
/dist
/node_modules

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

.env

================================================
FILE: .prettierrc
================================================
{
  "singleQuote": true,
  "trailingComma": "all"
}

================================================
FILE: README.md
================================================
 <p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications, heavily inspired by <a href="https://angular.io" target="blank">Angular</a>.
 </p>

## Description
A Simple CRUD Web API with NestJs, Postgres, Sequelize ORM. 

## Installation

```bash
$ git clone https://github.com/onwuvic/nest-blog-api.git
```

## Running the app

- cd into `nest-blog-api`
- run `npm install`
- set up your postgres database
- rename `.env.sample` to `.env` and populate the required parameters
- run `npm run start:dev`

```bash
# development
$ npm run start

# watch mode
$ npm run start:dev

# production mode
$ npm run start:prod
```


## Stay in touch

- Author - Victor Onwuzor
- Twitter - [@victoronwuzor](https://twitter.com/victoronwuzor)

## License
[MIT licensed](LICENSE).


================================================
FILE: nest-cli.json
================================================
{
  "language": "ts",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src"
}


================================================
FILE: package.json
================================================
{
  "name": "nest-blog-api",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "license": "MIT",
  "scripts": {
    "build": "rimraf dist && tsc -p tsconfig.build.json",
    "format": "prettier --write \"src/**/*.ts\"",
    "start": "ts-node -r tsconfig-paths/register src/main.ts",
    "start:dev": "tsc-watch -p tsconfig.build.json --onSuccess \"node dist/main.js\"",
    "start:debug": "tsc-watch -p tsconfig.build.json --onSuccess \"node --inspect-brk dist/main.js\"",
    "start:prod": "node dist/main.js",
    "lint": "tslint -p tsconfig.json -c tslint.json",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@nestjs/common": "^6.0.0",
    "@nestjs/config": "0.4.0",
    "@nestjs/core": "^6.0.0",
    "@nestjs/jwt": "7.0.0",
    "@nestjs/passport": "7.0.0",
    "@nestjs/platform-express": "^6.0.0",
    "bcrypt": "^5.0.0",
    "class-transformer": "0.2.3",
    "class-validator": "0.12.2",
    "dotenv": "8.2.0",
    "passport": "0.4.1",
    "passport-jwt": "4.0.0",
    "passport-local": "1.0.0",
    "pg": "7.18.2",
    "pg-hstore": "2.3.3",
    "reflect-metadata": "^0.1.12",
    "rimraf": "^2.6.2",
    "rxjs": "^6.3.3",
    "sequelize": "5.21.5",
    "sequelize-typescript": "1.1.0"
  },
  "devDependencies": {
    "@nestjs/testing": "^6.0.0",
    "@types/express": "4.16.1",
    "@types/jest": "24.0.11",
    "@types/node": "11.13.4",
    "@types/passport-jwt": "3.0.3",
    "@types/passport-local": "1.0.33",
    "@types/sequelize": "4.28.8",
    "@types/supertest": "2.0.7",
    "jest": "24.7.1",
    "prettier": "1.17.0",
    "supertest": "4.0.2",
    "ts-jest": "^26.4.1",
    "ts-node": "8.1.0",
    "tsc-watch": "2.2.1",
    "tsconfig-paths": "3.8.0",
    "tslint": "5.16.0",
    "typescript": "3.7.2"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".spec.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}


================================================
FILE: src/app.controller.spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';

import { AppController } from './app.controller';
import { AppService } from './app.service';

describe('AppController', () => {
  let appController: AppController;

  beforeEach(async () => {
    const app: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [AppService],
    }).compile();

    appController = app.get<AppController>(AppController);
  });

  describe('root', () => {
    it('should return "Hello World!"', () => {
      expect(appController.getHello()).toBe('Hello World!');
    });
  });
});


================================================
FILE: src/app.controller.ts
================================================
import { Controller, Get } from '@nestjs/common';

import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}


================================================
FILE: src/app.module.ts
================================================
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './core/database/database.module';
import { UsersModule } from './modules/users/users.module';
import { AuthModule } from './modules/auth/auth.module';
import { PostsModule } from './modules/posts/posts.module';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    DatabaseModule,
    UsersModule,
    AuthModule,
    PostsModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}


================================================
FILE: src/app.service.ts
================================================
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}


================================================
FILE: src/core/constants/index.ts
================================================
export const SEQUELIZE = 'SEQUELIZE';
export const DEVELOPMENT = 'development';
export const TEST = 'test';
export const PRODUCTION = 'production';
export const USER_REPOSITORY = 'USER_REPOSITORY';
export const POST_REPOSITORY = 'POST_REPOSITORY';


================================================
FILE: src/core/database/database.config.ts
================================================
import * as dotenv from 'dotenv';

import { IDatabaseConfig } from './interfaces/dbConfig.interface';

dotenv.config();

export const databaseConfig: IDatabaseConfig = {
    development: {
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME_DEVELOPMENT,
        host: process.env.DB_HOST,
        port: process.env.DB_PORT,
        dialect: process.env.DB_DIALECT,
    },
    test: {
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME_TEST,
        host: process.env.DB_HOST,
        port: process.env.DB_PORT,
        dialect: process.env.DB_DIALECT,
    },
    production: {
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME_PRODUCTION,
        host: process.env.DB_HOST,
        dialect: process.env.DB_DIALECT,
    },
};


================================================
FILE: src/core/database/database.module.ts
================================================
import { Module } from '@nestjs/common';

import { databaseProviders } from './database.providers';

@Module({
    providers: [...databaseProviders],
    exports: [...databaseProviders],
})
export class DatabaseModule { }


================================================
FILE: src/core/database/database.providers.ts
================================================
import { Sequelize } from 'sequelize-typescript';

import { SEQUELIZE, DEVELOPMENT, TEST, PRODUCTION } from '../constants';
import { databaseConfig } from './database.config';
import { User } from '../../modules/users/user.entity';
import { Post } from '../../modules/posts/post.entity';

export const databaseProviders = [
    {
        provide: SEQUELIZE,
        useFactory: async () => {
            let config;
            switch (process.env.NODE_ENV) {
                case DEVELOPMENT:
                    config = databaseConfig.development;
                    break;
                case TEST:
                    config = databaseConfig.test;
                    break;
                case PRODUCTION:
                    config = databaseConfig.production;
                    break;
                default:
                    config = databaseConfig.development;
            }
            const sequelize = new Sequelize(config);
            sequelize.addModels([User, Post]);
            await sequelize.sync();
            return sequelize;
        },
    },
];


================================================
FILE: src/core/database/interfaces/dbConfig.interface.ts
================================================
export interface IDatabaseConfigAttributes {
    username?: string;
    password?: string;
    database?: string;
    host?: string;
    port?: number | string;
    dialect?: string;
    urlDatabase?: string;
}

export interface IDatabaseConfig {
    development: IDatabaseConfigAttributes;
    test: IDatabaseConfigAttributes;
    production: IDatabaseConfigAttributes;
}

================================================
FILE: src/core/guards/doesUserExist.guard.ts
================================================
import { CanActivate, ExecutionContext, Injectable, ForbiddenException } from '@nestjs/common';
import { Observable } from 'rxjs';

import { UsersService } from '../../modules/users/users.service';

@Injectable()
export class DoesUserExist implements CanActivate {
    constructor(private readonly userService: UsersService) { }

    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
        const request = context.switchToHttp().getRequest();
        return this.validateRequest(request);
    }

    async validateRequest(request) {
        const userExist = await this.userService.findOneByEmail(request.body.email);
        if (userExist) {
            throw new ForbiddenException('This email already exist');
        }
        return true;
    }
}


================================================
FILE: src/core/pipes/validate.pipe.ts
================================================
import { Injectable, ArgumentMetadata, BadRequestException, ValidationPipe, UnprocessableEntityException } from '@nestjs/common';

@Injectable()
export class ValidateInputPipe extends ValidationPipe {
    public async transform(value, metadata: ArgumentMetadata) {
        try {
            return await super.transform(value, metadata);
        } catch (e) {
            if (e instanceof BadRequestException) {
                throw new UnprocessableEntityException(this.handleError(e.message.message));
            }
        }
    }

    private handleError(errors) {
        return errors.map(error => error.constraints);
    }
}


================================================
FILE: src/main.ts
================================================
import { NestFactory } from '@nestjs/core';

import { AppModule } from './app.module';
import { ValidateInputPipe } from './core/pipes/validate.pipe';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix('api/v1');
  // handle all user input validation globally
  app.useGlobalPipes(new ValidateInputPipe());
  await app.listen(3000);
}
bootstrap();


================================================
FILE: src/modules/auth/auth.controller.spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';

import { AuthController } from './auth.controller';

describe('Auth Controller', () => {
  let controller: AuthController;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [AuthController],
    }).compile();

    controller = module.get<AuthController>(AuthController);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });
});


================================================
FILE: src/modules/auth/auth.controller.ts
================================================
import { Controller, Body, Post, UseGuards, Request } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

import { AuthService } from './auth.service';
import { UserDto } from '../users/dto/user.dto';
import { DoesUserExist } from '../../core/guards/doesUserExist.guard';

@Controller('auth')
export class AuthController {
    constructor(private authService: AuthService) { }

    @UseGuards(AuthGuard('local'))
    @Post('login')
    async login(@Request() req) {
        return await this.authService.login(req.user);
    }

    @UseGuards(DoesUserExist)
    @Post('signup')
    async signUp(@Body() user: UserDto) {
        return await this.authService.create(user);
    }
}


================================================
FILE: src/modules/auth/auth.module.ts
================================================
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';

import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UsersModule } from '../users/users.module';
import { LocalStrategy } from './local.strategy';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    PassportModule,
    UsersModule,
    JwtModule.register({
      secret: process.env.JWTKEY,
      signOptions: { expiresIn: process.env.TOKEN_EXPIRATION },
    }),
  ],
  providers: [
    AuthService,
    LocalStrategy,
    JwtStrategy,
  ],
  controllers: [AuthController],
})
export class AuthModule {}


================================================
FILE: src/modules/auth/auth.service.spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';

import { AuthService } from './auth.service';

describe('AuthService', () => {
  let service: AuthService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [AuthService],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});


================================================
FILE: src/modules/auth/auth.service.ts
================================================
import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

import { UsersService } from '../users/users.service';

@Injectable()
export class AuthService {
    constructor(
        private readonly userService: UsersService,
        private readonly jwtService: JwtService,
    ) { }

    async validateUser(username: string, pass: string) {
        // find if user exist with this email
        const user = await this.userService.findOneByEmail(username);
        if (!user) {
            return null;
        }

        // find if user password match
        const match = await this.comparePassword(pass, user.password);

        if (!match) {
            return null;
        }

        // tslint:disable-next-line: no-string-literal
        const { password, ...result } = user['dataValues'];
        return result;
    }

    public async login(user) {
        const token = await this.generateToken(user);
        return { user, token };
    }

    public async create(user) {
        // hash the password
        const pass = await this.hashPassword(user.password);

        // create the user
        const newUser = await this.userService.create({ ...user, password: pass });

        // tslint:disable-next-line: no-string-literal
        const { password, ...result } = newUser['dataValues'];

        // generate token
        const token = await this.generateToken(result);

        // return the user and the token
        return { user: result, token };
    }

    private async generateToken(user) {
        const token = await this.jwtService.signAsync(user);
        return token;
    }

    private async hashPassword(password) {
        const hash = await bcrypt.hash(password, 10);
        return hash;
    }

    private async comparePassword(enteredPassword, dbPassword) {
        const match = await bcrypt.compare(enteredPassword, dbPassword);
        return match;
    }
}


================================================
FILE: src/modules/auth/jwt.strategy.ts
================================================
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';

import { UsersService } from '../users/users.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(private readonly userService: UsersService) {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: false,
            secretOrKey: process.env.JWTKEY,
        });
    }

    async validate(payload: any) {
        // check if user in the token actually exist
        const user = await this.userService.findOneById(payload.id);
        if (!user) {
            throw new UnauthorizedException('You are not authorized to perform the operation');
        }
        return payload;
    }
}


================================================
FILE: src/modules/auth/local.strategy.ts
================================================
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';

import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(private readonly authService: AuthService) {
        super();
    }

    async validate(username: string, password: string): Promise<any> {
        const user = await this.authService.validateUser(username, password);
        if (!user) {
            throw new UnauthorizedException('Invalid user credentials');
        }
        return user;
    }
}


================================================
FILE: src/modules/posts/dto/post.dto.ts
================================================
import { IsNotEmpty, MinLength } from 'class-validator';

export class PostDto {

    @IsNotEmpty()
    @MinLength(4)
    readonly title: string;

    @IsNotEmpty()
    readonly body: string;
}


================================================
FILE: src/modules/posts/post.entity.ts
================================================
import { Table, Column, Model, DataType, ForeignKey, BelongsTo } from 'sequelize-typescript';

import { User } from '../users/user.entity';

@Table
export class Post extends Model<Post> {
    @Column({
        type: DataType.STRING,
        allowNull: false,
    })
    title: string;

    @Column({
        type: DataType.TEXT,
        allowNull: false,
    })
    body: string;

    @ForeignKey(() => User)
    @Column({
        type: DataType.INTEGER,
        allowNull: false,
    })
    userId: number;

    @BelongsTo(() => User)
    user: User;
}


================================================
FILE: src/modules/posts/posts.controller.spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';

import { PostsController } from './posts.controller';

describe('Posts Controller', () => {
  let controller: PostsController;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [PostsController],
    }).compile();

    controller = module.get<PostsController>(PostsController);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });
});


================================================
FILE: src/modules/posts/posts.controller.ts
================================================
import { Controller, Get, Post, Put, Delete, Param, Body, NotFoundException, UseGuards, Request } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

import { PostsService } from './posts.service';
import { Post as PostEntity } from './post.entity';
import { PostDto } from './dto/post.dto';

@Controller('posts')
export class PostsController {
    constructor(private readonly postService: PostsService) { }

    @Get()
    async findAll() {
        // get all posts in the db
        return await this.postService.findAll();
    }

    @Get(':id')
    async findOne(@Param('id') id: number): Promise<PostEntity> {
        // find the post with this id
        const post = await this.postService.findOne(id);

        // if the post doesn't exit in the db, throw a 404 error
        if (!post) {
            throw new NotFoundException('This Post doesn\'t exist');
        }

        // if post exist, return the post
        return post;
    }

    @UseGuards(AuthGuard('jwt'))
    @Post()
    async create(@Body() post: PostDto, @Request() req): Promise<PostEntity> {
        // create a new post and return the newly created post
        return await this.postService.create(post, req.user.id);
    }

    @UseGuards(AuthGuard('jwt'))
    @Put(':id')
    async update(@Param('id') id: number, @Body() post: PostDto, @Request() req): Promise<PostEntity> {
        // get the number of row affected and the updated post
        const { numberOfAffectedRows, updatedPost } = await this.postService.update(id, post, req.user.id);

        // if the number of row affected is zero, it means the post doesn't exist in our db
        if (numberOfAffectedRows === 0) {
            throw new NotFoundException('This Post doesn\'t exist');
        }

        // return the updated post
        return updatedPost;
    }

    @UseGuards(AuthGuard('jwt'))
    @Delete(':id')
    async remove(@Param('id') id: number, @Request() req) {
        // delete the post with this id
        const deleted = await this.postService.delete(id, req.user.id);

        // if the number of row affected is zero, then the post doesn't exist in our db
        if (deleted === 0) {
            throw new NotFoundException('This Post doesn\'t exist');
        }

        // return success message
        return 'Successfully deleted';
    }
}


================================================
FILE: src/modules/posts/posts.module.ts
================================================
import { Module } from '@nestjs/common';

import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import { postsProviders } from './posts.providers';

@Module({
  providers: [PostsService, ...postsProviders],
  controllers: [PostsController],
})
export class PostsModule {}


================================================
FILE: src/modules/posts/posts.providers.ts
================================================
import { Post } from './post.entity';
import { POST_REPOSITORY } from '../../core/constants';

export const postsProviders = [
    {
        provide: POST_REPOSITORY,
        useValue: Post,
    },
];


================================================
FILE: src/modules/posts/posts.service.spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';

import { PostsService } from './posts.service';

describe('PostsService', () => {
  let service: PostsService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [PostsService],
    }).compile();

    service = module.get<PostsService>(PostsService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});


================================================
FILE: src/modules/posts/posts.service.ts
================================================
import { Injectable, Inject } from '@nestjs/common';

import { Post } from './post.entity';
import { PostDto } from './dto/post.dto';
import { User } from '../users/user.entity';
import { POST_REPOSITORY } from '../../core/constants';

@Injectable()
export class PostsService {
    constructor(@Inject(POST_REPOSITORY) private readonly postRepository: typeof Post) { }

    async create(post: PostDto, userId): Promise<Post> {
        return await this.postRepository.create<Post>({ ...post, userId });
    }

    async findAll(): Promise<Post[]> {
        return await this.postRepository.findAll<Post>({
            include: [{ model: User, attributes: { exclude: ['password'] } }],
        });
    }

    async findOne(id): Promise<Post> {
        return await this.postRepository.findOne({
            where: { id },
            include: [{ model: User, attributes: { exclude: ['password'] } }],
        });
    }

    async delete(id, userId) {
        return await this.postRepository.destroy({ where: { id, userId } });
    }

    async update(id, data, userId) {
        const [numberOfAffectedRows, [updatedPost]] = await this.postRepository.update({ ...data }, { where: { id, userId }, returning: true });
        return { numberOfAffectedRows, updatedPost };
    }
}


================================================
FILE: src/modules/users/dto/user.dto.ts
================================================
import { IsNotEmpty, MinLength, IsEmail, IsEnum } from 'class-validator';

enum Gender {
    MALE = 'male',
    FEMALE = 'female',
}

export class UserDto {

    @IsNotEmpty()
    readonly name: string;

    @IsNotEmpty()
    @IsEmail()
    readonly email: string;

    @IsNotEmpty()
    @MinLength(6)
    readonly password: string;

    @IsNotEmpty()
    @IsEnum(Gender, {
        message: 'gender must be either male or female',
    })
    readonly gender: Gender;
}


================================================
FILE: src/modules/users/user.entity.ts
================================================
import { Table, Column, Model, DataType } from 'sequelize-typescript';

@Table
export class User extends Model<User> {
    @Column({
        type: DataType.STRING,
        allowNull: false,
    })
    name: string;
    @Column({
        type: DataType.STRING,
        unique: true,
        allowNull: false,
    })
    email: string;
    @Column({
        type: DataType.STRING,
        allowNull: false,
    })
    password: string;
    @Column({
        type: DataType.ENUM,
        values: ['male', 'female'],
        allowNull: false,
    })
    gender: string;
}


================================================
FILE: src/modules/users/users.module.ts
================================================
import { Module } from '@nestjs/common';

import { UsersService } from './users.service';
import { usersProviders } from './users.providers';

@Module({
  providers: [UsersService, ...usersProviders],
  exports: [UsersService],
})
export class UsersModule {}


================================================
FILE: src/modules/users/users.providers.ts
================================================
import { User } from './user.entity';
import { USER_REPOSITORY } from '../../core/constants';

export const usersProviders = [
    {
        provide: USER_REPOSITORY,
        useValue: User,
    },
];


================================================
FILE: src/modules/users/users.service.spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';

import { UsersService } from './users.service';

describe('UsersService', () => {
  let service: UsersService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UsersService],
    }).compile();

    service = module.get<UsersService>(UsersService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});


================================================
FILE: src/modules/users/users.service.ts
================================================
import { Injectable, Inject } from '@nestjs/common';

import { User } from './user.entity';
import { UserDto } from './dto/user.dto';
import { USER_REPOSITORY } from '../../core/constants';

@Injectable()
export class UsersService {
    constructor(@Inject(USER_REPOSITORY) private readonly userRepository: typeof User) { }

    async create(user: UserDto): Promise<User> {
        return await this.userRepository.create<User>(user);
    }

    async findOneByEmail(email: string): Promise<User> {
        return await this.userRepository.findOne<User>({ where: { email } });
    }

    async findOneById(id: number): Promise<User> {
        return await this.userRepository.findOne<User>({ where: { id } });
    }

}


================================================
FILE: test/app.e2e-spec.ts
================================================
import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () => {
  let app;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Hello World!');
  });
});


================================================
FILE: test/jest-e2e.json
================================================
{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": ".",
  "testEnvironment": "node",
  "testRegex": ".e2e-spec.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  }
}


================================================
FILE: tsconfig.build.json
================================================
{
  "extends": "./tsconfig.json",
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true
  },
  "exclude": ["node_modules", "dist"]
}


================================================
FILE: tslint.json
================================================
{
  "defaultSeverity": "error",
  "extends": ["tslint:recommended"],
  "jsRules": {
    "no-unused-expression": true
  },
  "rules": {
    "quotemark": [true, "single"],
    "member-access": [false],
    "ordered-imports": [false],
    "max-line-length": [true, 150],
    "member-ordering": [false],
    "interface-name": [false],
    "arrow-parens": false,
    "object-literal-sort-keys": false
  },
  "rulesDirectory": []
}
Download .txt
gitextract_35nzldb_/

├── .gitignore
├── .prettierrc
├── README.md
├── nest-cli.json
├── package.json
├── src/
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── core/
│   │   ├── constants/
│   │   │   └── index.ts
│   │   ├── database/
│   │   │   ├── database.config.ts
│   │   │   ├── database.module.ts
│   │   │   ├── database.providers.ts
│   │   │   └── interfaces/
│   │   │       └── dbConfig.interface.ts
│   │   ├── guards/
│   │   │   └── doesUserExist.guard.ts
│   │   └── pipes/
│   │       └── validate.pipe.ts
│   ├── main.ts
│   └── modules/
│       ├── auth/
│       │   ├── auth.controller.spec.ts
│       │   ├── auth.controller.ts
│       │   ├── auth.module.ts
│       │   ├── auth.service.spec.ts
│       │   ├── auth.service.ts
│       │   ├── jwt.strategy.ts
│       │   └── local.strategy.ts
│       ├── posts/
│       │   ├── dto/
│       │   │   └── post.dto.ts
│       │   ├── post.entity.ts
│       │   ├── posts.controller.spec.ts
│       │   ├── posts.controller.ts
│       │   ├── posts.module.ts
│       │   ├── posts.providers.ts
│       │   ├── posts.service.spec.ts
│       │   └── posts.service.ts
│       └── users/
│           ├── dto/
│           │   └── user.dto.ts
│           ├── user.entity.ts
│           ├── users.module.ts
│           ├── users.providers.ts
│           ├── users.service.spec.ts
│           └── users.service.ts
├── test/
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
├── tsconfig.json
└── tslint.json
Download .txt
SYMBOL INDEX (68 symbols across 23 files)

FILE: src/app.controller.ts
  class AppController (line 6) | class AppController {
    method constructor (line 7) | constructor(private readonly appService: AppService) {}
    method getHello (line 10) | getHello(): string {

FILE: src/app.module.ts
  class AppModule (line 22) | class AppModule {}

FILE: src/app.service.ts
  class AppService (line 4) | class AppService {
    method getHello (line 5) | getHello(): string {

FILE: src/core/constants/index.ts
  constant SEQUELIZE (line 1) | const SEQUELIZE = 'SEQUELIZE';
  constant DEVELOPMENT (line 2) | const DEVELOPMENT = 'development';
  constant TEST (line 3) | const TEST = 'test';
  constant PRODUCTION (line 4) | const PRODUCTION = 'production';
  constant USER_REPOSITORY (line 5) | const USER_REPOSITORY = 'USER_REPOSITORY';
  constant POST_REPOSITORY (line 6) | const POST_REPOSITORY = 'POST_REPOSITORY';

FILE: src/core/database/database.module.ts
  class DatabaseModule (line 9) | class DatabaseModule { }

FILE: src/core/database/interfaces/dbConfig.interface.ts
  type IDatabaseConfigAttributes (line 1) | interface IDatabaseConfigAttributes {
  type IDatabaseConfig (line 11) | interface IDatabaseConfig {

FILE: src/core/guards/doesUserExist.guard.ts
  class DoesUserExist (line 7) | class DoesUserExist implements CanActivate {
    method constructor (line 8) | constructor(private readonly userService: UsersService) { }
    method canActivate (line 10) | canActivate(
    method validateRequest (line 17) | async validateRequest(request) {

FILE: src/core/pipes/validate.pipe.ts
  class ValidateInputPipe (line 4) | class ValidateInputPipe extends ValidationPipe {
    method transform (line 5) | public async transform(value, metadata: ArgumentMetadata) {
    method handleError (line 15) | private handleError(errors) {

FILE: src/main.ts
  function bootstrap (line 6) | async function bootstrap() {

FILE: src/modules/auth/auth.controller.ts
  class AuthController (line 9) | class AuthController {
    method constructor (line 10) | constructor(private authService: AuthService) { }
    method login (line 14) | async login(@Request() req) {
    method signUp (line 20) | async signUp(@Body() user: UserDto) {

FILE: src/modules/auth/auth.module.ts
  class AuthModule (line 27) | class AuthModule {}

FILE: src/modules/auth/auth.service.ts
  class AuthService (line 8) | class AuthService {
    method constructor (line 9) | constructor(
    method validateUser (line 14) | async validateUser(username: string, pass: string) {
    method login (line 33) | public async login(user) {
    method create (line 38) | public async create(user) {
    method generateToken (line 55) | private async generateToken(user) {
    method hashPassword (line 60) | private async hashPassword(password) {
    method comparePassword (line 65) | private async comparePassword(enteredPassword, dbPassword) {

FILE: src/modules/auth/jwt.strategy.ts
  class JwtStrategy (line 8) | class JwtStrategy extends PassportStrategy(Strategy) {
    method constructor (line 9) | constructor(private readonly userService: UsersService) {
    method validate (line 17) | async validate(payload: any) {

FILE: src/modules/auth/local.strategy.ts
  class LocalStrategy (line 8) | class LocalStrategy extends PassportStrategy(Strategy) {
    method constructor (line 9) | constructor(private readonly authService: AuthService) {
    method validate (line 13) | async validate(username: string, password: string): Promise<any> {

FILE: src/modules/posts/dto/post.dto.ts
  class PostDto (line 3) | class PostDto {

FILE: src/modules/posts/post.entity.ts
  class Post (line 6) | class Post extends Model<Post> {

FILE: src/modules/posts/posts.controller.ts
  class PostsController (line 9) | class PostsController {
    method constructor (line 10) | constructor(private readonly postService: PostsService) { }
    method findAll (line 13) | async findAll() {
    method findOne (line 19) | async findOne(@Param('id') id: number): Promise<PostEntity> {
    method create (line 34) | async create(@Body() post: PostDto, @Request() req): Promise<PostEntit...
    method update (line 41) | async update(@Param('id') id: number, @Body() post: PostDto, @Request(...
    method remove (line 56) | async remove(@Param('id') id: number, @Request() req) {

FILE: src/modules/posts/posts.module.ts
  class PostsModule (line 11) | class PostsModule {}

FILE: src/modules/posts/posts.service.ts
  class PostsService (line 9) | class PostsService {
    method constructor (line 10) | constructor(@Inject(POST_REPOSITORY) private readonly postRepository: ...
    method create (line 12) | async create(post: PostDto, userId): Promise<Post> {
    method findAll (line 16) | async findAll(): Promise<Post[]> {
    method findOne (line 22) | async findOne(id): Promise<Post> {
    method delete (line 29) | async delete(id, userId) {
    method update (line 33) | async update(id, data, userId) {

FILE: src/modules/users/dto/user.dto.ts
  type Gender (line 3) | enum Gender {
  class UserDto (line 8) | class UserDto {

FILE: src/modules/users/user.entity.ts
  class User (line 4) | class User extends Model<User> {

FILE: src/modules/users/users.module.ts
  class UsersModule (line 10) | class UsersModule {}

FILE: src/modules/users/users.service.ts
  class UsersService (line 8) | class UsersService {
    method constructor (line 9) | constructor(@Inject(USER_REPOSITORY) private readonly userRepository: ...
    method create (line 11) | async create(user: UserDto): Promise<User> {
    method findOneByEmail (line 15) | async findOneByEmail(email: string): Promise<User> {
    method findOneById (line 19) | async findOneById(id: number): Promise<User> {
Condensed preview — 43 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (30K chars).
[
  {
    "path": ".gitignore",
    "chars": 381,
    "preview": "# 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*"
  },
  {
    "path": ".prettierrc",
    "chars": 51,
    "preview": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "README.md",
    "chars": 866,
    "preview": " <p align=\"center\">A progressive <a href=\"http://nodejs.org\" target=\"blank\">Node.js</a> framework for building efficient"
  },
  {
    "path": "nest-cli.json",
    "chars": 84,
    "preview": "{\n  \"language\": \"ts\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "package.json",
    "chars": 2255,
    "preview": "{\n  \"name\": \"nest-blog-api\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"scripts\":"
  },
  {
    "path": "src/app.controller.spec.ts",
    "chars": 618,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\n\nimport { AppController } from './app.controller';\nimport { AppSe"
  },
  {
    "path": "src/app.controller.ts",
    "chars": 275,
    "preview": "import { Controller, Get } from '@nestjs/common';\n\nimport { AppService } from './app.service';\n\n@Controller()\nexport cla"
  },
  {
    "path": "src/app.module.ts",
    "chars": 659,
    "preview": "import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\n\nimport { AppController } from '"
  },
  {
    "path": "src/app.service.ts",
    "chars": 142,
    "preview": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getHello(): string {\n    return "
  },
  {
    "path": "src/core/constants/index.ts",
    "chars": 248,
    "preview": "export const SEQUELIZE = 'SEQUELIZE';\nexport const DEVELOPMENT = 'development';\nexport const TEST = 'test';\nexport const"
  },
  {
    "path": "src/core/database/database.config.ts",
    "chars": 920,
    "preview": "import * as dotenv from 'dotenv';\n\nimport { IDatabaseConfig } from './interfaces/dbConfig.interface';\n\ndotenv.config();\n"
  },
  {
    "path": "src/core/database/database.module.ts",
    "chars": 222,
    "preview": "import { Module } from '@nestjs/common';\n\nimport { databaseProviders } from './database.providers';\n\n@Module({\n    provi"
  },
  {
    "path": "src/core/database/database.providers.ts",
    "chars": 1081,
    "preview": "import { Sequelize } from 'sequelize-typescript';\n\nimport { SEQUELIZE, DEVELOPMENT, TEST, PRODUCTION } from '../constant"
  },
  {
    "path": "src/core/database/interfaces/dbConfig.interface.ts",
    "chars": 372,
    "preview": "export interface IDatabaseConfigAttributes {\n    username?: string;\n    password?: string;\n    database?: string;\n    ho"
  },
  {
    "path": "src/core/guards/doesUserExist.guard.ts",
    "chars": 810,
    "preview": "import { CanActivate, ExecutionContext, Injectable, ForbiddenException } from '@nestjs/common';\nimport { Observable } fr"
  },
  {
    "path": "src/core/pipes/validate.pipe.ts",
    "chars": 633,
    "preview": "import { Injectable, ArgumentMetadata, BadRequestException, ValidationPipe, UnprocessableEntityException } from '@nestjs"
  },
  {
    "path": "src/main.ts",
    "chars": 400,
    "preview": "import { NestFactory } from '@nestjs/core';\n\nimport { AppModule } from './app.module';\nimport { ValidateInputPipe } from"
  },
  {
    "path": "src/modules/auth/auth.controller.spec.ts",
    "chars": 480,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\n\nimport { AuthController } from './auth.controller';\n\ndescribe('A"
  },
  {
    "path": "src/modules/auth/auth.controller.ts",
    "chars": 698,
    "preview": "import { Controller, Body, Post, UseGuards, Request } from '@nestjs/common';\nimport { AuthGuard } from '@nestjs/passport"
  },
  {
    "path": "src/modules/auth/auth.module.ts",
    "chars": 714,
    "preview": "import { Module } from '@nestjs/common';\nimport { PassportModule } from '@nestjs/passport';\nimport { JwtModule } from '@"
  },
  {
    "path": "src/modules/auth/auth.service.spec.ts",
    "chars": 447,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\n\nimport { AuthService } from './auth.service';\n\ndescribe('AuthSer"
  },
  {
    "path": "src/modules/auth/auth.service.ts",
    "chars": 1964,
    "preview": "import { Injectable } from '@nestjs/common';\nimport * as bcrypt from 'bcrypt';\nimport { JwtService } from '@nestjs/jwt';"
  },
  {
    "path": "src/modules/auth/jwt.strategy.ts",
    "chars": 872,
    "preview": "import { ExtractJwt, Strategy } from 'passport-jwt';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Injec"
  },
  {
    "path": "src/modules/auth/local.strategy.ts",
    "chars": 657,
    "preview": "import { Strategy } from 'passport-local';\nimport { PassportStrategy } from '@nestjs/passport';\nimport { Injectable, Una"
  },
  {
    "path": "src/modules/posts/dto/post.dto.ts",
    "chars": 194,
    "preview": "import { IsNotEmpty, MinLength } from 'class-validator';\n\nexport class PostDto {\n\n    @IsNotEmpty()\n    @MinLength(4)\n  "
  },
  {
    "path": "src/modules/posts/post.entity.ts",
    "chars": 554,
    "preview": "import { Table, Column, Model, DataType, ForeignKey, BelongsTo } from 'sequelize-typescript';\n\nimport { User } from '../"
  },
  {
    "path": "src/modules/posts/posts.controller.spec.ts",
    "chars": 487,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\n\nimport { PostsController } from './posts.controller';\n\ndescribe("
  },
  {
    "path": "src/modules/posts/posts.controller.ts",
    "chars": 2337,
    "preview": "import { Controller, Get, Post, Put, Delete, Param, Body, NotFoundException, UseGuards, Request } from '@nestjs/common';"
  },
  {
    "path": "src/modules/posts/posts.module.ts",
    "chars": 320,
    "preview": "import { Module } from '@nestjs/common';\n\nimport { PostsService } from './posts.service';\nimport { PostsController } fro"
  },
  {
    "path": "src/modules/posts/posts.providers.ts",
    "chars": 201,
    "preview": "import { Post } from './post.entity';\nimport { POST_REPOSITORY } from '../../core/constants';\n\nexport const postsProvide"
  },
  {
    "path": "src/modules/posts/posts.service.spec.ts",
    "chars": 454,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\n\nimport { PostsService } from './posts.service';\n\ndescribe('Posts"
  },
  {
    "path": "src/modules/posts/posts.service.ts",
    "chars": 1278,
    "preview": "import { Injectable, Inject } from '@nestjs/common';\n\nimport { Post } from './post.entity';\nimport { PostDto } from './d"
  },
  {
    "path": "src/modules/users/dto/user.dto.ts",
    "chars": 469,
    "preview": "import { IsNotEmpty, MinLength, IsEmail, IsEnum } from 'class-validator';\n\nenum Gender {\n    MALE = 'male',\n    FEMALE ="
  },
  {
    "path": "src/modules/users/user.entity.ts",
    "chars": 568,
    "preview": "import { Table, Column, Model, DataType } from 'sequelize-typescript';\n\n@Table\nexport class User extends Model<User> {\n "
  },
  {
    "path": "src/modules/users/users.module.ts",
    "chars": 259,
    "preview": "import { Module } from '@nestjs/common';\n\nimport { UsersService } from './users.service';\nimport { usersProviders } from"
  },
  {
    "path": "src/modules/users/users.providers.ts",
    "chars": 201,
    "preview": "import { User } from './user.entity';\nimport { USER_REPOSITORY } from '../../core/constants';\n\nexport const usersProvide"
  },
  {
    "path": "src/modules/users/users.service.spec.ts",
    "chars": 454,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\n\nimport { UsersService } from './users.service';\n\ndescribe('Users"
  },
  {
    "path": "src/modules/users/users.service.ts",
    "chars": 719,
    "preview": "import { Injectable, Inject } from '@nestjs/common';\n\nimport { User } from './user.entity';\nimport { UserDto } from './d"
  },
  {
    "path": "test/app.e2e-spec.ts",
    "chars": 561,
    "preview": "import { Test, TestingModule } from '@nestjs/testing';\nimport * as request from 'supertest';\nimport { AppModule } from '"
  },
  {
    "path": "test/jest-e2e.json",
    "chars": 183,
    "preview": "{\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \".\",\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-sp"
  },
  {
    "path": "tsconfig.build.json",
    "chars": 97,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 336,
    "preview": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecorat"
  },
  {
    "path": "tslint.json",
    "chars": 426,
    "preview": "{\n  \"defaultSeverity\": \"error\",\n  \"extends\": [\"tslint:recommended\"],\n  \"jsRules\": {\n    \"no-unused-expression\": true\n  }"
  }
]

About this extraction

This page contains the full source code of the onwuvic/nest-blog-api GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 43 files (25.3 KB), approximately 7.3k tokens, and a symbol index with 68 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!