diff --git a/src/app.module.ts b/src/app.module.ts index c0b89fc..803089d 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,6 +7,7 @@ import * as Joi from 'joi'; import {UsersModule} from "./users/user.module"; import {AuthenticationModule} from "./authentication/authentication.module"; import { PostsModule } from './posts/posts.module'; +import { CategoriesModule } from './categories/categories.module'; @Module({ imports: [ @@ -35,7 +36,8 @@ import { PostsModule } from './posts/posts.module'; }), UsersModule, AuthenticationModule, - PostsModule + PostsModule, + CategoriesModule ], controllers: [AppController], providers: [AppService], diff --git a/src/categories/categories.controller.ts b/src/categories/categories.controller.ts new file mode 100644 index 0000000..8c865d6 --- /dev/null +++ b/src/categories/categories.controller.ts @@ -0,0 +1,34 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { CategoriesService } from './categories.service'; +import { CreateCategoryDto } from './dto/create-category.dto'; +import { UpdateCategoryDto } from './dto/update-category.dto'; + +@Controller('categories') +export class CategoriesController { + constructor(private readonly categoriesService: CategoriesService) {} + + @Post() + create(@Body() createCategoryDto: CreateCategoryDto) { + return this.categoriesService.create(createCategoryDto); + } + + @Get() + findAll() { + return this.categoriesService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.categoriesService.findOne(+id); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() updateCategoryDto: UpdateCategoryDto) { + return this.categoriesService.update(+id, updateCategoryDto); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.categoriesService.remove(+id); + } +} diff --git a/src/categories/categories.module.ts b/src/categories/categories.module.ts new file mode 100644 index 0000000..3499b76 --- /dev/null +++ b/src/categories/categories.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { CategoriesService } from './categories.service'; +import { CategoriesController } from './categories.controller'; + +@Module({ + controllers: [CategoriesController], + providers: [CategoriesService], +}) +export class CategoriesModule {} diff --git a/src/categories/categories.service.ts b/src/categories/categories.service.ts new file mode 100644 index 0000000..92f3051 --- /dev/null +++ b/src/categories/categories.service.ts @@ -0,0 +1,70 @@ +import { Injectable } from '@nestjs/common'; +import { CreateCategoryDto } from './dto/create-category.dto'; +import { UpdateCategoryDto } from './dto/update-category.dto'; +import {InjectRepository} from "@nestjs/typeorm"; +import Post from "../posts/entities/post.entity"; +import {Repository} from "typeorm"; +import Category from "./entities/category.entity"; +import {CategoryNotFoundException} from "./exception/categoryNotFound.exception"; + +@Injectable() +export class CategoriesService { + + constructor( + @InjectRepository(Category) private repo: Repository, + ) { + } + + + + getAllCategories() { + return this.repo.find({ relations: ['posts'] }); +} + +async getCategoryById(id: number) { + const category = await this.repo.findOne({ + where: { id }, + relations: { + posts: true, + } + }); + if (category) { + return category; + } + throw new CategoryNotFoundException(id); +} + +async updateCategory(id: number, category: UpdateCategoryDto) { + await this.repo.update(id, category); + const updatedCategory = await this.repo.findOne({ + where: { id }, + relations: { + posts: true, + } + }); + if (updatedCategory) { + return updatedCategory + } + throw new CategoryNotFoundException(id); +} + + create(createCategoryDto: CreateCategoryDto) { + return 'This action adds a new category'; + } + + findAll() { + return `This action returns all categories`; + } + + findOne(id: number) { + return `This action returns a #${id} category`; + } + + update(id: number, updateCategoryDto: UpdateCategoryDto) { + return `This action updates a #${id} category`; + } + + remove(id: number) { + return `This action removes a #${id} category`; + } +} diff --git a/src/categories/dto/create-category.dto.ts b/src/categories/dto/create-category.dto.ts new file mode 100644 index 0000000..4f8ca2f --- /dev/null +++ b/src/categories/dto/create-category.dto.ts @@ -0,0 +1 @@ +export class CreateCategoryDto {} diff --git a/src/categories/dto/update-category.dto.ts b/src/categories/dto/update-category.dto.ts new file mode 100644 index 0000000..d713b9b --- /dev/null +++ b/src/categories/dto/update-category.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateCategoryDto } from './create-category.dto'; + +export class UpdateCategoryDto extends PartialType(CreateCategoryDto) {} diff --git a/src/categories/entities/category.entity.ts b/src/categories/entities/category.entity.ts new file mode 100644 index 0000000..3069f5c --- /dev/null +++ b/src/categories/entities/category.entity.ts @@ -0,0 +1,16 @@ +import {Column, Entity, ManyToMany, PrimaryGeneratedColumn} from 'typeorm'; +import Post from "../../posts/entities/post.entity"; + +@Entity() +class Category { + @PrimaryGeneratedColumn() + public id: number; + + @Column() + public name: string; + + @ManyToMany(() => Post, (post: Post) => post.categories) + public posts: Post[]; +} + +export default Category; \ No newline at end of file diff --git a/src/categories/exception/categoryNotFound.exception.ts b/src/categories/exception/categoryNotFound.exception.ts new file mode 100644 index 0000000..6b569b7 --- /dev/null +++ b/src/categories/exception/categoryNotFound.exception.ts @@ -0,0 +1,7 @@ +import { NotFoundException } from '@nestjs/common'; + +export class CategoryNotFoundException extends NotFoundException { + constructor(categoryId: number) { + super(`Category with id ${categoryId} not found`); + } +} \ No newline at end of file diff --git a/src/posts/entities/post.entity.ts b/src/posts/entities/post.entity.ts index 54fbf02..7f4ba36 100644 --- a/src/posts/entities/post.entity.ts +++ b/src/posts/entities/post.entity.ts @@ -1 +1,29 @@ -export class Post {} +import {Column, Entity, ManyToOne, PrimaryGeneratedColumn, ManyToMany, JoinTable} from 'typeorm'; +import User from "../../users/user.entity"; +import Category from "../../categories/entities/category.entity"; + +@Entity() +class Post { + @PrimaryGeneratedColumn() + public id: number; + + @Column() + public title: string; + + @Column() + public content: string; + + @Column({nullable: true}) + public category?: string; + + @ManyToOne(() => User, (author: User) => author.posts) + public author: User; + + + @ManyToMany(() => Category, (category: Category) => category.posts) + @JoinTable() + public categories: Category[]; + +} + +export default Post; \ No newline at end of file diff --git a/src/posts/exception/postNotFund.exception.ts b/src/posts/exception/postNotFound.exception.ts similarity index 68% rename from src/posts/exception/postNotFund.exception.ts rename to src/posts/exception/postNotFound.exception.ts index 11c6935..97cc719 100644 --- a/src/posts/exception/postNotFund.exception.ts +++ b/src/posts/exception/postNotFound.exception.ts @@ -1,6 +1,6 @@ import { NotFoundException } from '@nestjs/common'; -class PostNotFoundException extends NotFoundException { +export class PostNotFoundException extends NotFoundException { constructor(postId: number) { super(`Post with id ${postId} not found`); } diff --git a/src/posts/posts.controller.spec.ts b/src/posts/posts.controller.spec.ts deleted file mode 100644 index 7027224..0000000 --- a/src/posts/posts.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { PostsController } from './posts.controller'; -import { PostsService } from './posts.service'; - -describe('PostsController', () => { - let controller: PostsController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [PostsController], - providers: [PostsService], - }).compile(); - - controller = module.get(PostsController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/src/posts/posts.controller.ts b/src/posts/posts.controller.ts index 6e719cd..ae42f03 100644 --- a/src/posts/posts.controller.ts +++ b/src/posts/posts.controller.ts @@ -1,34 +1,38 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; -import { PostsService } from './posts.service'; -import { CreatePostDto } from './dto/create-post.dto'; -import { UpdatePostDto } from './dto/update-post.dto'; +import {Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, Req} from '@nestjs/common'; +import {PostsService} from './posts.service'; +import {CreatePostDto} from './dto/create-post.dto'; +import {UpdatePostDto} from './dto/update-post.dto'; +import JwtAuthenticationGuard from "../authentication/jwt-authentication.guard"; +import RequestWithUser from "../authentication/requestWithUser.interface"; @Controller('posts') export class PostsController { - constructor(private readonly postsService: PostsService) {} + constructor(private readonly postsService: PostsService) { + } - @Post() - create(@Body() createPostDto: CreatePostDto) { - return this.postsService.create(createPostDto); - } + @Post() + @UseGuards(JwtAuthenticationGuard) + async createPost(@Body() post: CreatePostDto, @Req() req: RequestWithUser) { + return this.postsService.createPost(post, req.user); + } - @Get() - findAll() { - return this.postsService.findAll(); - } + @Get() + findAll() { + return this.postsService.findAll(); + } - @Get(':id') - findOne(@Param('id') id: string) { - return this.postsService.findOne(+id); - } + @Get(':id') + findOne(@Param('id') id: string) { + return this.postsService.findOne(+id); + } - @Patch(':id') - update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) { - return this.postsService.update(+id, updatePostDto); - } + @Patch(':id') + update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) { + return this.postsService.update(+id, updatePostDto); + } - @Delete(':id') - remove(@Param('id') id: string) { - return this.postsService.remove(+id); - } + @Delete(':id') + remove(@Param('id') id: string) { + return this.postsService.remove(+id); + } } diff --git a/src/posts/posts.service.spec.ts b/src/posts/posts.service.spec.ts deleted file mode 100644 index e152158..0000000 --- a/src/posts/posts.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -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); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/src/posts/posts.service.ts b/src/posts/posts.service.ts index bc90f24..52a6481 100644 --- a/src/posts/posts.service.ts +++ b/src/posts/posts.service.ts @@ -1,26 +1,74 @@ -import { Injectable } from '@nestjs/common'; -import { CreatePostDto } from './dto/create-post.dto'; -import { UpdatePostDto } from './dto/update-post.dto'; +import {Injectable} from '@nestjs/common'; +import {CreatePostDto} from './dto/create-post.dto'; +import {UpdatePostDto} from './dto/update-post.dto'; +import User from "../users/user.entity"; +import {InjectRepository} from "@nestjs/typeorm"; +import {Repository} from "typeorm"; +import Post from './entities/post.entity'; +import {PostNotFoundException} from "./exception/postNotFound.exception"; @Injectable() export class PostsService { - create(createPostDto: CreatePostDto) { - return 'This action adds a new post'; - } - findAll() { - return `This action returns all posts`; - } + constructor( + @InjectRepository(Post) private repo: Repository, + ) { + } - findOne(id: number) { - return `This action returns a #${id} post`; - } + async createPost(post: CreatePostDto, user: User) { + const newPost = this.repo.create({ + ...post, + author: user + }); + await this.repo.save(newPost); + return newPost; + } - update(id: number, updatePostDto: UpdatePostDto) { - return `This action updates a #${id} post`; - } - remove(id: number) { - return `This action removes a #${id} post`; - } + getAllPosts() { + return this.repo.find({relations: ['author']}); + } + + async getPostById(id: number) { + const post = await this.repo.findOne( + { + where: {id}, + relations: {author: true} + } + ); + if (post) { + return post; + } + throw new PostNotFoundException(id); + } + + async updatePost(id: number, post: UpdatePostDto) { + await this.repo.update(id, post); + const updatedPost = await this.repo.findOne({ + + where: {id}, + relations: {author: true} + + }); + if (updatedPost) { + return updatedPost + } + throw new PostNotFoundException(id); + } + + findAll() { + return `This action returns all posts`; + } + + findOne(id: number) { + return `This action returns a #${id} post`; + } + + update(id: number, updatePostDto: UpdatePostDto) { + return `This action updates a #${id} post`; + } + + remove(id: number) { + return `This action removes a #${id} post`; + } } diff --git a/src/users/address.entity.ts b/src/users/address.entity.ts new file mode 100644 index 0000000..81faf08 --- /dev/null +++ b/src/users/address.entity.ts @@ -0,0 +1,22 @@ +import {Column, Entity, OneToOne, PrimaryGeneratedColumn} from 'typeorm'; +import User from "./user.entity"; + +@Entity() +class Address { + @PrimaryGeneratedColumn() + public id: number; + + @Column() + public street: string; + + @Column() + public city: string; + + @Column() + public country: string; + + @OneToOne(() => User, (user: User) => user.address) + public user: User; +} + +export default Address; \ No newline at end of file diff --git a/src/users/user.entity.ts b/src/users/user.entity.ts index 520b99a..8c29aff 100644 --- a/src/users/user.entity.ts +++ b/src/users/user.entity.ts @@ -1,5 +1,7 @@ -import {Column, Entity, PrimaryGeneratedColumn} from 'typeorm'; +import {Column, Entity, PrimaryGeneratedColumn, OneToOne, JoinColumn, OneToMany} from 'typeorm'; import {Exclude, Expose} from 'class-transformer'; +import Address from "./address.entity"; +import Post from "../posts/entities/post.entity"; @Entity() class User { @@ -17,6 +19,18 @@ class User { @Column() public password: string; + @OneToOne(() => Address, { + eager: true, + cascade: true + }) + @JoinColumn() + public address: Address; + + + @OneToMany(() => Post, (post: Post) => post.author) + public posts: Post[]; + + @Column({ nullable: true, })