Archived
solutions system
This commit is contained in:
6 files changed
+157
-2
No files matched your search
@@ -13,10 +13,14 @@ import { IssuesService } from './issues/issues.service';
|
|||||||
import { IssueType } from './issues/entities/issue-type.enum';
|
import { IssueType } from './issues/entities/issue-type.enum';
|
||||||
import { CreateIssueDto } from './issues/dto/create-issue.dto';
|
import { CreateIssueDto } from './issues/dto/create-issue.dto';
|
||||||
import { CreateIssueCommentDto } from './issues/dto/create-issue-comment.dto';
|
import { CreateIssueCommentDto } from './issues/dto/create-issue-comment.dto';
|
||||||
|
import { SolutionsService } from './solutions/solutions.service';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(private readonly issues: IssuesService) {}
|
constructor(
|
||||||
|
private readonly issues: IssuesService,
|
||||||
|
private readonly solutions: SolutionsService,
|
||||||
|
) {}
|
||||||
|
|
||||||
@Get('/issues/problems')
|
@Get('/issues/problems')
|
||||||
listProblems() {
|
listProblems() {
|
||||||
@@ -36,7 +40,14 @@ export class AppController {
|
|||||||
async getIssue(@Param('id', ParseUUIDPipe) id: string) {
|
async getIssue(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
const data = await this.issues.findOne(id).then((i) => i.toDto());
|
const data = await this.issues.findOne(id).then((i) => i.toDto());
|
||||||
const comments = await this.issues.getCommentsForIssue(id);
|
const comments = await this.issues.getCommentsForIssue(id);
|
||||||
return { data, comments };
|
const solution =
|
||||||
|
(await this.solutions.getForIssue(id))?.toList() ?? undefined;
|
||||||
|
return { data, comments, solution };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/issues/:id/solution')
|
||||||
|
async getSolution(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
|
return this.solutions.getForIssue(id).then((i) => i.toDto());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/issues')
|
@Post('/issues')
|
||||||
@@ -64,6 +75,18 @@ export class AppController {
|
|||||||
await this.issues.dislike(id);
|
await this.issues.dislike(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('/issues/:id/solution/like')
|
||||||
|
@HttpCode(HttpStatus.ACCEPTED)
|
||||||
|
async addLikeToSolution(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
|
await this.solutions.like(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/issues/:id/solution/dislike')
|
||||||
|
@HttpCode(HttpStatus.ACCEPTED)
|
||||||
|
async addDislikeToSolution(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
|
await this.solutions.dislike(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Delete('/issues/:id/like')
|
@Delete('/issues/:id/like')
|
||||||
@HttpCode(HttpStatus.ACCEPTED)
|
@HttpCode(HttpStatus.ACCEPTED)
|
||||||
async removeLike(@Param('id', ParseUUIDPipe) id: string) {
|
async removeLike(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
@@ -75,4 +98,16 @@ export class AppController {
|
|||||||
async removeDislike(@Param('id', ParseUUIDPipe) id: string) {
|
async removeDislike(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
await this.issues.dislike(id, true);
|
await this.issues.dislike(id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Delete('/issues/:id/solution/like')
|
||||||
|
@HttpCode(HttpStatus.ACCEPTED)
|
||||||
|
async removeLikeToSolution(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
|
await this.solutions.like(id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete('/issues/:id/solution/dislike')
|
||||||
|
@HttpCode(HttpStatus.ACCEPTED)
|
||||||
|
async removeDislikeToSolution(@Param('id', ParseUUIDPipe) id: string) {
|
||||||
|
await this.solutions.dislike(id, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
|||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { IssuesModule } from './issues/issues.module';
|
import { IssuesModule } from './issues/issues.module';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
|
import { SolutionsModule } from './solutions/solutions.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
@@ -17,6 +18,7 @@ import { AppController } from './app.controller';
|
|||||||
synchronize: process.env.NODE_ENV !== 'production',
|
synchronize: process.env.NODE_ENV !== 'production',
|
||||||
}),
|
}),
|
||||||
IssuesModule,
|
IssuesModule,
|
||||||
|
SolutionsModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { IsString, MaxLength, MinLength } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateSolutionDto {
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(32)
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(255)
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Issue } from 'src/issues/entities/issue.entity';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('solutions')
|
||||||
|
export class Solution {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => Issue, { lazy: true, onDelete: 'CASCADE' })
|
||||||
|
issue: Promise<Issue>;
|
||||||
|
|
||||||
|
@Column({ default: 0 })
|
||||||
|
likes: number;
|
||||||
|
|
||||||
|
@Column({ default: 0 })
|
||||||
|
dislikes: number;
|
||||||
|
|
||||||
|
async toDto() {
|
||||||
|
return {
|
||||||
|
...this.toList(),
|
||||||
|
description: this.description,
|
||||||
|
issue: (await this.issue).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toList() {
|
||||||
|
return {
|
||||||
|
title: this.title,
|
||||||
|
username: this.username,
|
||||||
|
likes: this.likes,
|
||||||
|
dislikes: this.dislikes,
|
||||||
|
createdAt: this.createdAt.toISOString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { SolutionsService } from './solutions.service';
|
||||||
|
import { IssuesModule } from 'src/issues/issues.module';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { Solution } from './entities/solution.entity';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [IssuesModule, TypeOrmModule.forFeature([Solution])],
|
||||||
|
providers: [SolutionsService],
|
||||||
|
exports: [SolutionsService],
|
||||||
|
})
|
||||||
|
export class SolutionsModule {}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { ConflictException, Injectable } from '@nestjs/common';
|
||||||
|
import { CreateSolutionDto } from './dto/create-solution.dto';
|
||||||
|
import { IssuesService } from 'src/issues/issues.service';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Solution } from './entities/solution.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SolutionsService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(Solution)
|
||||||
|
private readonly repository: Repository<Solution>,
|
||||||
|
private readonly issues: IssuesService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async create(issueId: string, createSolutionDto: CreateSolutionDto) {
|
||||||
|
if ((await this.getForIssue(issueId)) !== null)
|
||||||
|
throw new ConflictException('This issue already has a solution');
|
||||||
|
const solution = this.repository.create({ ...createSolutionDto });
|
||||||
|
const issue = await this.issues.findOne(issueId);
|
||||||
|
solution.issue = Promise.resolve(issue);
|
||||||
|
return this.repository.save(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getForIssue(issueId: string): Promise<Solution | null> {
|
||||||
|
return this.repository.findOneBy({ issue: { id: issueId } });
|
||||||
|
}
|
||||||
|
|
||||||
|
async like(issueId: string, remove?: boolean) {
|
||||||
|
const ent = await this.getForIssue(issueId);
|
||||||
|
ent.likes = remove ? ent.likes - 1 : ent.likes + 1;
|
||||||
|
return this.repository.save(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
async dislike(issueId: string, remove?: boolean) {
|
||||||
|
const ent = await this.getForIssue(issueId);
|
||||||
|
ent.dislikes = remove ? ent.dislikes - 1 : ent.dislikes + 1;
|
||||||
|
return this.repository.save(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user