diff --git a/apps/server/config/typeorm.config.ts b/apps/server/config/typeorm.config.ts index 7df4673..a17433d 100644 --- a/apps/server/config/typeorm.config.ts +++ b/apps/server/config/typeorm.config.ts @@ -4,6 +4,8 @@ import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm'; import { Task } from '@/task/domain/task.entity'; import { Section } from '@/task/domain/section.entity'; import { Account } from '@/account/entity/account.entity'; +import { Project } from '@/project/entity/project.entity'; +import { Contributor } from '@/project/entity/contributor.entity'; @Injectable() export class TypeormConfig implements TypeOrmOptionsFactory { @@ -17,7 +19,7 @@ export class TypeormConfig implements TypeOrmOptionsFactory { username: this.configService.get('DATABASE_USER'), password: this.configService.get('DATABASE_PASSWORD'), database: this.configService.get('DATABASE_NAME'), - entities: [Task, Section, Account], + entities: [Task, Section, Account, Project, Contributor], synchronize: true, ssl: { rejectUnauthorized: false, diff --git a/apps/server/src/account/dto/create-user.dto.ts b/apps/server/src/account/dto/create-user.dto.ts index ec17983..a8bcde1 100644 --- a/apps/server/src/account/dto/create-user.dto.ts +++ b/apps/server/src/account/dto/create-user.dto.ts @@ -1,9 +1,11 @@ -import { IsEmail, IsString, Length } from 'class-validator'; +import { IsEmail, IsNotEmpty, IsString, Length } from 'class-validator'; export class CreateUserDto { + @IsNotEmpty() @IsEmail() username: string; + @IsNotEmpty() @IsString() @Length(8, 15) password: string; diff --git a/apps/server/src/account/entity/account.entity.ts b/apps/server/src/account/entity/account.entity.ts index 741d65d..058240f 100644 --- a/apps/server/src/account/entity/account.entity.ts +++ b/apps/server/src/account/entity/account.entity.ts @@ -1,7 +1,8 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { EntityTimestamp } from '@/common/entity-timestamp.entity'; @Entity() -export class Account { +export class Account extends EntityTimestamp { @PrimaryGeneratedColumn() id: number; diff --git a/apps/server/src/app.module.ts b/apps/server/src/app.module.ts index dfa1b4b..c5d423e 100644 --- a/apps/server/src/app.module.ts +++ b/apps/server/src/app.module.ts @@ -10,6 +10,7 @@ import { AppController } from './app.controller'; import { HttpLoggingInterceptor } from './common/httpLog.Interceptor'; import { AllExceptionsFilter } from './common/allException.filter'; import { AccountModule } from './account/account.module'; +import { ProjectModule } from './project/project.module'; @Module({ imports: [ @@ -24,6 +25,7 @@ import { AccountModule } from './account/account.module'; }), TaskModule, AccountModule, + ProjectModule, ], controllers: [AppController], providers: [ diff --git a/apps/server/src/common/entity-timestamp.entity.ts b/apps/server/src/common/entity-timestamp.entity.ts new file mode 100644 index 0000000..60b1981 --- /dev/null +++ b/apps/server/src/common/entity-timestamp.entity.ts @@ -0,0 +1,9 @@ +import { CreateDateColumn, UpdateDateColumn } from 'typeorm'; + +export class EntityTimestamp { + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/apps/server/src/project/controller/project.controller.ts b/apps/server/src/project/controller/project.controller.ts new file mode 100644 index 0000000..9230372 --- /dev/null +++ b/apps/server/src/project/controller/project.controller.ts @@ -0,0 +1,17 @@ +import { Body, Controller, Post, UseGuards } from '@nestjs/common'; +import { ProjectService } from '../service/project.service'; +import { AccessTokenGuard } from '@/account/guard/accessToken.guard'; +import { CreateProjectRequest } from '../dto/create-project-request.dto'; +import { AuthUser } from '@/account/decorator/authUser.decorator'; +import { Account } from '@/account/entity/account.entity'; + +@UseGuards(AccessTokenGuard) +@Controller('projects') +export class ProjectController { + constructor(private projectService: ProjectService) {} + + @Post() + create(@AuthUser() user: Account, @Body() body: CreateProjectRequest) { + return this.projectService.create(user.id, body.title); + } +} diff --git a/apps/server/src/project/dto/create-project-request.dto.ts b/apps/server/src/project/dto/create-project-request.dto.ts new file mode 100644 index 0000000..3ff1b1b --- /dev/null +++ b/apps/server/src/project/dto/create-project-request.dto.ts @@ -0,0 +1,8 @@ +import { IsNotEmpty, IsString, Length } from 'class-validator'; + +export class CreateProjectRequest { + @IsNotEmpty() + @IsString() + @Length(1, 20) + title: string; +} diff --git a/apps/server/src/project/dto/create-project-response.dto.ts b/apps/server/src/project/dto/create-project-response.dto.ts new file mode 100644 index 0000000..5364723 --- /dev/null +++ b/apps/server/src/project/dto/create-project-response.dto.ts @@ -0,0 +1,12 @@ +import { Project } from '../entity/project.entity'; + +export class CreateProjectResponse { + id: number; + + title: string; + + constructor(project: Project) { + this.id = project.id; + this.title = project.title; + } +} diff --git a/apps/server/src/project/entity/contributor.entity.ts b/apps/server/src/project/entity/contributor.entity.ts new file mode 100644 index 0000000..44fcce9 --- /dev/null +++ b/apps/server/src/project/entity/contributor.entity.ts @@ -0,0 +1,22 @@ +import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { ContributorStatus } from '../enum/contributor-status.enum'; +import { ProjectRole } from '../enum/project-role.enum'; +import { EntityTimestamp } from '@/common/entity-timestamp.entity'; + +@Entity() +export class Contributor extends EntityTimestamp { + @PrimaryGeneratedColumn() + id: number; + + @Column() + userId: number; + + @Column() + projectId: number; + + @Column({ type: 'enum', enum: ContributorStatus }) + status: ContributorStatus; + + @Column({ type: 'enum', enum: ProjectRole }) + role: ProjectRole; +} diff --git a/apps/server/src/project/entity/project.entity.ts b/apps/server/src/project/entity/project.entity.ts new file mode 100644 index 0000000..f884334 --- /dev/null +++ b/apps/server/src/project/entity/project.entity.ts @@ -0,0 +1,11 @@ +import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { EntityTimestamp } from '@/common/entity-timestamp.entity'; + +@Entity() +export class Project extends EntityTimestamp { + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; +} diff --git a/apps/server/src/project/enum/contributor-status.enum.ts b/apps/server/src/project/enum/contributor-status.enum.ts new file mode 100644 index 0000000..f672730 --- /dev/null +++ b/apps/server/src/project/enum/contributor-status.enum.ts @@ -0,0 +1,5 @@ +export enum ContributorStatus { + PENDING = 'PENDING', + ACCEPTED = 'ACCEPTED', + REJECTED = 'REJECTED', +} diff --git a/apps/server/src/project/enum/project-role.enum.ts b/apps/server/src/project/enum/project-role.enum.ts new file mode 100644 index 0000000..739abf6 --- /dev/null +++ b/apps/server/src/project/enum/project-role.enum.ts @@ -0,0 +1,4 @@ +export enum ProjectRole { + ADMIN = 'ADMIN', + GUEST = 'GUEST', +} diff --git a/apps/server/src/project/project.module.ts b/apps/server/src/project/project.module.ts new file mode 100644 index 0000000..c363849 --- /dev/null +++ b/apps/server/src/project/project.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ProjectService } from './service/project.service'; +import { ProjectController } from './controller/project.controller'; +import { Project } from './entity/project.entity'; +import { Contributor } from './entity/contributor.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Project, Contributor])], + controllers: [ProjectController], + providers: [ProjectService], +}) +export class ProjectModule {} diff --git a/apps/server/src/project/service/project.service.ts b/apps/server/src/project/service/project.service.ts new file mode 100644 index 0000000..a4e1c2d --- /dev/null +++ b/apps/server/src/project/service/project.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Project } from '../entity/project.entity'; +import { Contributor } from '../entity/contributor.entity'; +import { ContributorStatus } from '../enum/contributor-status.enum'; +import { ProjectRole } from '../enum/project-role.enum'; +import { CreateProjectResponse } from '../dto/create-project-response.dto'; + +@Injectable() +export class ProjectService { + constructor( + @InjectRepository(Project) private projectRepository: Repository, + @InjectRepository(Contributor) private contributorRepository: Repository + ) {} + + async create(userId: number, title: string) { + const project = await this.projectRepository.save({ title }); + await this.contributorRepository.save({ + userId, + projectId: project.id, + status: ContributorStatus.ACCEPTED, + role: ProjectRole.ADMIN, + }); + return new CreateProjectResponse(project); + } +}