Skip to content

Commit

Permalink
Merge pull request #11 from kir-dev/band-crud
Browse files Browse the repository at this point in the history
Band crud
  • Loading branch information
DankaMarci authored Dec 12, 2024
2 parents 78be1c5 + 45bc8f0 commit 2c74b4e
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "BandMembership" ALTER COLUMN "status" SET DEFAULT 'PENDING';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
Warnings:
- The `genres` column on the `Band` table would be dropped and recreated. This will lead to data loss if there is data in the column.
*/
-- AlterTable
ALTER TABLE "Band" DROP COLUMN "genres",
ADD COLUMN "genres" TEXT[];
62 changes: 28 additions & 34 deletions apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
provider = "prisma-client-js"
}
Expand All @@ -13,12 +7,6 @@ datasource db {
url = env("DATABASE_URL")
}

enum Role {
USER
GATEKEEPER
ADMIN
}

model User {
id Int @id @default(autoincrement())
name String
Expand All @@ -28,18 +16,18 @@ model User {
roomNumber String
role Role
bandMemberships BandMembership[]
reservations Reservation[] @relation("Reservations")
gateKeeping Reservation[] @relation("GateKeeping")
cardRight CardRight?
profilePicture ProfilePicture?
gateKeeping Reservation[] @relation("GateKeeping")
reservations Reservation[] @relation("Reservations")
}

model ProfilePicture {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int @unique
mimeType String
profileImage Bytes
user User @relation(fields: [userId], references: [id])
}

model CardRight {
Expand All @@ -48,47 +36,37 @@ model CardRight {
user User @relation(fields: [userId], references: [id])
}

enum ReservationStatus {
OVERTIME
NORMAL
}

model Reservation {
id Int @id @default(autoincrement())
user User? @relation("Reservations", fields: [userId], references: [id])
userId Int?
band Band? @relation(fields: [bandId], references: [id])
bandId Int?
startTime DateTime
endTime DateTime
gateKeeper User? @relation("GateKeeping", fields: [gateKeeperId], references: [id])
gateKeeperId Int?
status ReservationStatus
band Band? @relation(fields: [bandId], references: [id])
gateKeeper User? @relation("GateKeeping", fields: [gateKeeperId], references: [id])
user User? @relation("Reservations", fields: [userId], references: [id])
}

model Band {
id Int @id @default(autoincrement())
name String
genres String?
members BandMembership[]
reservations Reservation[]
email String?
webPage String?
description String?
}

enum BandMembershipStatus {
PENDING
ACCEPTED
genres String[]
members BandMembership[]
reservations Reservation[]
}

model BandMembership {
id Int @id @default(autoincrement())
user User? @relation(fields: [userId], references: [id])
userId Int?
band Band? @relation(fields: [bandId], references: [id])
bandId Int?
status BandMembershipStatus
status BandMembershipStatus @default(PENDING)
band Band? @relation(fields: [bandId], references: [id])
user User? @relation(fields: [userId], references: [id])
}

model Comment {
Expand All @@ -104,3 +82,19 @@ model Period {
startDate DateTime
endDate DateTime
}

enum Role {
USER
GATEKEEPER
ADMIN
}

enum ReservationStatus {
OVERTIME
NORMAL
}

enum BandMembershipStatus {
PENDING
ACCEPTED
}
3 changes: 2 additions & 1 deletion apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { PrismaModule } from 'nestjs-prisma';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BandModule } from './band/band.module';
import { CommentsModule } from './comments/comments.module';
import { ReservationsModule } from './reservations/reservations.module';
import { UsersModule } from './users/users.module';

@Module({
imports: [PrismaModule.forRoot({ isGlobal: true }), UsersModule, ReservationsModule, CommentsModule],
imports: [PrismaModule.forRoot({ isGlobal: true }), UsersModule, ReservationsModule, CommentsModule, BandModule],
controllers: [AppController],
providers: [AppService],
})
Expand Down
55 changes: 55 additions & 0 deletions apps/backend/src/band/band.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from '@nestjs/common';

import { BandService } from './band.service';
import { CreateBandDto } from './dto/create-band.dto';
import { UpdateBandDto } from './dto/update-band.dto';

@Controller('band')
export class BandController {
constructor(private readonly bandService: BandService) {}

@Post()
create(@Body() createBandDto: CreateBandDto) {
return this.bandService.create(createBandDto);
}

@Get()
findAll() {
return this.bandService.findAll();
}

@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.bandService.findOne(id);
}

@Patch(':id')
update(@Param('id', ParseIntPipe) id: number, @Body() updateBandDto: UpdateBandDto) {
return this.bandService.update(id, updateBandDto);
}

@Delete(':id')
remove(@Param('id', ParseIntPipe) id: number) {
return this.bandService.remove(id);
}

@Get(':id/members')
findMembers(@Param('id', ParseIntPipe) id: number) {
return this.bandService.findMembers(id);
}

@Post(':id/members/:userId')
addMember(@Param('id', ParseIntPipe) bandId: number, @Param('userId', ParseIntPipe) userId: number) {
return this.bandService.addMember(bandId, userId);
}

@Delete(':id/members/:userId')
removeMember(@Param('id', ParseIntPipe) bandId: number, @Param('userId', ParseIntPipe) userId: number) {
return this.bandService.removeMember(bandId, userId);
}

@Patch(':id/members/:userId')
approveMember(@Param('id', ParseIntPipe) bandId: number, @Param('userId', ParseIntPipe) userId: number) {
return this.bandService.approveMember(bandId, userId);
}
}
10 changes: 10 additions & 0 deletions apps/backend/src/band/band.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';

import { BandController } from './band.controller';
import { BandService } from './band.service';

@Module({
controllers: [BandController],
providers: [BandService],
})
export class BandModule {}
93 changes: 93 additions & 0 deletions apps/backend/src/band/band.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { BandMembership, BandMembershipStatus } from '@prisma/client';
import { PrismaService } from 'nestjs-prisma';
import { User } from 'src/users/entities/user.entity';

import { CreateBandDto } from './dto/create-band.dto';
import { UpdateBandDto } from './dto/update-band.dto';
import { Band } from './entities/band.entity';

@Injectable()
export class BandService {
constructor(private readonly prisma: PrismaService) {}

async create(createBandDto: CreateBandDto): Promise<Band> {
return await this.prisma.band.create({ data: createBandDto });
}

async findAll(): Promise<Band[]> {
const res = await this.prisma.band.findMany({
include: { members: { include: { user: { select: { name: true } } } } },
});
return res;
}

async findOne(id: number): Promise<Band> {
try {
const res = await this.prisma.band.findUniqueOrThrow({ where: { id } });
return res;
} catch (error) {
throw new NotFoundException('No band found');
}
}

async update(id: number, updateBandDto: UpdateBandDto): Promise<Band> {
return await this.prisma.band.update({ where: { id }, data: updateBandDto });
}

async remove(id: number): Promise<Band> {
try {
const res = await this.prisma.band.delete({ where: { id } });
return res;
} catch (error) {
throw new NotFoundException('No bands found');
}
}

async findMembers(id: number): Promise<User[]> {
try {
const bandmemberships = await this.prisma.bandMembership.findMany({
where: { bandId: id },
include: { user: true },
});
return bandmemberships.map((membership) => membership.user);
} catch (error) {
throw new NotFoundException('No members found');
}
}

async addMember(bandId: number, userId: number): Promise<BandMembership> {
try {
const res = await this.prisma.bandMembership.create({
data: { band: { connect: { id: bandId } }, user: { connect: { id: userId } } },
});
return res;
} catch (error) {
throw new NotFoundException('Member could not be added');
}
}

async removeMember(bandId: number, userId: number) {
try {
const res = await this.prisma.bandMembership.deleteMany({ where: { bandId, userId } });
const members = await this.findMembers(bandId);
if (members.length === 0) {
await this.remove(bandId);
}
return res;
} catch (error) {
throw new NotFoundException('No member found');
}
}

async approveMember(bandId: number, userId: number) {
try {
return await this.prisma.bandMembership.updateMany({
where: { bandId, userId },
data: { status: BandMembershipStatus.ACCEPTED },
});
} catch (error) {
throw new NotFoundException('No member found');
}
}
}
5 changes: 5 additions & 0 deletions apps/backend/src/band/dto/create-band.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { OmitType } from '@nestjs/swagger';

import { Band } from '../entities/band.entity';

export class CreateBandDto extends OmitType(Band, ['id']) {}
5 changes: 5 additions & 0 deletions apps/backend/src/band/dto/update-band.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PartialType } from '@nestjs/mapped-types';

import { CreateBandDto } from './create-band.dto';

export class UpdateBandDto extends PartialType(CreateBandDto) {}
27 changes: 27 additions & 0 deletions apps/backend/src/band/entities/band.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { IsNotEmpty, IsNumber, IsOptional, IsPositive, IsString } from 'class-validator';

export class Band {
@IsNotEmpty()
@IsNumber()
@IsPositive()
id: number;

@IsNotEmpty()
name: string;

@IsOptional()
@IsString()
email: string;

@IsOptional()
@IsString()
webPage: string;

@IsOptional()
@IsString()
description: string;

@IsOptional()
@IsString()
genres: string[];
}
2 changes: 1 addition & 1 deletion apps/backend/src/users/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { OmitType } from '@nestjs/swagger';

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

export class CreateUserDto extends OmitType(User, ['id']) {}
export class CreateUserDto extends OmitType(User, ['id', 'cardRight', 'profilePicture']) {}
8 changes: 5 additions & 3 deletions apps/backend/src/users/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Role } from '@prisma/client';
import { CardRight, ProfilePicture, Role } from '@prisma/client';
import { IsBoolean, IsEmail, IsEnum, IsNotEmpty, IsNumber, IsOptional, IsPositive, IsString } from 'class-validator';

export class User {
Expand Down Expand Up @@ -27,7 +27,9 @@ export class User {
@IsEnum(Role)
role: Role;

cardRight: any;
@IsOptional()
cardRight?: CardRight;

profilePicture: any;
@IsOptional()
profilePicture?: ProfilePicture;
}
2 changes: 1 addition & 1 deletion apps/backend/src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class UsersService {

async update(id: number, updateUserDto: UpdateUserDto) {
try {
return this.prisma.user.update({
return await this.prisma.user.update({
where: {
id,
},
Expand Down

0 comments on commit 2c74b4e

Please sign in to comment.