diff --git a/src/server/workspace/src/app.module.ts b/src/server/workspace/src/app.module.ts index 50816190..e8cab2dc 100644 --- a/src/server/workspace/src/app.module.ts +++ b/src/server/workspace/src/app.module.ts @@ -6,12 +6,16 @@ import { AuthModule } from './auth/auth.module'; import { UserModule } from './user/user.module'; import { WorkspaceModule } from './workspace/workspace.module'; import { OrganisationModule } from './organisation/organisation.module'; +import { MaterialModule } from './material/material.module'; +import { ScheduleModule } from './schedule/schedule.module'; @Module({ imports: [ AuthModule, UserModule, WorkspaceModule, + MaterialModule, + ScheduleModule, OrganisationModule, ConfigModule.forRoot({ envFilePath: ['.env'] }), MongooseModule.forRoot('mongodb://localhost/cc'), diff --git a/src/server/workspace/src/auth/auth.service.ts b/src/server/workspace/src/auth/auth.service.ts index 32e1e077..6a8cebc2 100644 --- a/src/server/workspace/src/auth/auth.service.ts +++ b/src/server/workspace/src/auth/auth.service.ts @@ -21,6 +21,8 @@ export class AuthService { const user = { sub: findUser._id, role: findUser.role, + workspaces: findUser.workspaces, + organisation: findUser.organisation, username: findUser.username, accessToken: this.jwtService.sign({ sub: findUser._id, @@ -28,7 +30,7 @@ export class AuthService { username: findUser.username, }), }; - + return user; } else { return null; diff --git a/src/server/workspace/src/material/dto/create-material.dto.ts b/src/server/workspace/src/material/dto/create-material.dto.ts new file mode 100644 index 00000000..7447abb1 --- /dev/null +++ b/src/server/workspace/src/material/dto/create-material.dto.ts @@ -0,0 +1,35 @@ +import { IsNotEmpty, IsString } from 'class-validator'; + +//this class just encapsulates data and does validation +export class CreateMaterialDto { + //this is the type + //either 3d model orpdf + @IsNotEmpty() + //@isBoolean(true) + type: boolean; + + //this is the workspace id + @IsNotEmpty() + @IsString() + workspace_id: string; + + //this is the lecturer id + @IsNotEmpty() + @IsString() + lecturer_id: string; + + //this is the title of the material + @IsNotEmpty() + @IsString() + title: string; + + //this is the description of the material + @IsNotEmpty() + @IsString() + description: string; + + //this is the filepath of the material + @IsNotEmpty() + @IsString() + file_path: string; +} diff --git a/src/server/workspace/src/material/dto/update-material.dto.ts b/src/server/workspace/src/material/dto/update-material.dto.ts new file mode 100644 index 00000000..48210596 --- /dev/null +++ b/src/server/workspace/src/material/dto/update-material.dto.ts @@ -0,0 +1,15 @@ +import { IsOptional, IsString, IsUrl } from 'class-validator'; + +export class UpdateMaterialDto { + @IsString() + @IsOptional() + file_path?: string; + + @IsUrl() + @IsOptional() + title?: string; + + @IsUrl() + @IsOptional() + description?: string; +} diff --git a/src/server/workspace/src/material/material.controller.spec.ts b/src/server/workspace/src/material/material.controller.spec.ts new file mode 100644 index 00000000..98cdc332 --- /dev/null +++ b/src/server/workspace/src/material/material.controller.spec.ts @@ -0,0 +1,93 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { MaterialController } from './material.controller'; +import { MaterialService } from './material.service'; +import { CreateMaterialDto } from './dto/create-material.dto'; +import { UpdateMaterialDto } from './dto/update-material.dto'; + +describe('MaterialController', () => { + let controller: MaterialController; + let service: MaterialService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [MaterialController], + providers: [ + { + provide: MaterialService, + useValue: { + create: jest.fn(), + findOne: jest.fn(), + findAllByWorkspaceId: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + }, + }, + ], + }).compile(); + + controller = module.get(MaterialController); + service = module.get(MaterialService); + }); + + describe('create', () => { + it('should call the create method of the service', async () => { + const createMaterialDto: CreateMaterialDto = { + type: true, + workspace_id: 'workspace-id-1', + lecturer_id: 'lecturer-id-1', + title: 'Test Material', + description: 'Test Description', + file_path: '/path/to/file.pdf', + }; + + await controller.create(createMaterialDto); + + expect(service.create).toHaveBeenCalledWith(createMaterialDto); + }); + }); + + describe('findOne', () => { + it('should call the findOne method of the service', async () => { + const id = 'test-id'; + + await controller.findOne(id); + + expect(service.findOne).toHaveBeenCalledWith(id); + }); + }); + + describe('findAllByWorkspaceId', () => { + it('should call the findAllByWorkspaceId method of the service', async () => { + const workspaceId = 'workspace-id-1'; + + await controller.findAllByWorkspaceId(workspaceId); + + expect(service.findAllByWorkspaceId).toHaveBeenCalledWith(workspaceId); + }); + }); + + describe('update', () => { + it('should call the update method of the service', async () => { + const id = 'test-id'; + const updateMaterialDto: UpdateMaterialDto = { + title: 'Updated Material', + description: 'Updated Description', + file_path: '/path/to/updated-file.pdf', + }; + + await controller.update(id, updateMaterialDto); + + expect(service.update).toHaveBeenCalledWith(id, updateMaterialDto); + }); + }); + + describe('delete', () => { + it('should call the delete method of the service', async () => { + const id = 'test-id'; + + await controller.delete(id); + + expect(service.delete).toHaveBeenCalledWith(id); + }); + }); +}); diff --git a/src/server/workspace/src/material/material.controller.ts b/src/server/workspace/src/material/material.controller.ts new file mode 100644 index 00000000..87bc8412 --- /dev/null +++ b/src/server/workspace/src/material/material.controller.ts @@ -0,0 +1,51 @@ +//this will handle all the http reqs and the responses + +import { + Get, + Put, + Body, + Post, + Param, + Delete, + Controller, +} from '@nestjs/common'; + +import { MaterialService } from './material.service'; +import { CreateMaterialDto } from './dto/create-material.dto'; +import { UpdateMaterialDto } from './dto/update-material.dto'; +import { Material } from '../schemas/material.schema'; + +@Controller('materials') +export class MaterialController { + constructor(private readonly materialService: MaterialService) {} + + @Post() + async create(@Body() createMaterialDto: CreateMaterialDto) { + return this.materialService.create(createMaterialDto); + } + + @Get(':id') + async findOne(@Param('id') id: string) { + return this.materialService.findOne(id); + } + + @Get('workspace/:workspaceId') + async findAllByWorkspaceId( + @Param('workspaceId') workspaceId: string, + ): Promise { + return this.materialService.findAllByWorkspaceId(workspaceId); + } + + @Put(':id') + async update( + @Param('id') id: string, + @Body() updateMaterialDto: UpdateMaterialDto, + ) { + return this.materialService.update(id, updateMaterialDto); + } + + @Delete(':id') + async delete(@Param('id') id: string) { + return this.materialService.delete(id); + } +} diff --git a/src/server/workspace/src/material/material.module.ts b/src/server/workspace/src/material/material.module.ts new file mode 100644 index 00000000..c6095f4a --- /dev/null +++ b/src/server/workspace/src/material/material.module.ts @@ -0,0 +1,20 @@ +//this will encapsulate the functionality and components + +import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; + +import { Material, MaterialSchema } from '../schemas/material.schema'; +import { MaterialService } from './material.service'; +import { MaterialController } from './material.controller'; + +@Module({ + imports: [ + MongooseModule.forFeature([ + { name: Material.name, schema: MaterialSchema }, + ]), + ], + providers: [MaterialService], + controllers: [MaterialController], + exports: [MaterialService], +}) +export class MaterialModule {} diff --git a/src/server/workspace/src/material/material.service.spec.ts b/src/server/workspace/src/material/material.service.spec.ts new file mode 100644 index 00000000..f20c8515 --- /dev/null +++ b/src/server/workspace/src/material/material.service.spec.ts @@ -0,0 +1,168 @@ +// material.service.spec.ts + +import { Test, TestingModule } from '@nestjs/testing'; +import { MaterialService } from './material.service'; +import { UpdateMaterialDto } from './dto/update-material.dto'; +import { Material } from '../schemas/material.schema'; +import { getModelToken } from '@nestjs/mongoose'; +import { Model, Query } from 'mongoose'; + +describe('MaterialService', () => { + let service: MaterialService; + let model: Model; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + MaterialService, + { + provide: getModelToken(Material.name), + useValue: { + create: jest.fn(), + findById: jest.fn(), + find: jest.fn(), + findByIdAndUpdate: jest.fn(), + findByIdAndDelete: jest.fn(), + }, + }, + ], + }).compile(); + + service = module.get(MaterialService); + model = module.get>(getModelToken(Material.name)); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + // describe('create', () => { + // it('should call the save method and return the created material', async () => { + // const createMaterialDto: CreateMaterialDto = { + // type: true, + // workspace_id: 'workspace-id-1', + // lecturer_id: 'lecturer-id-1', + // title: 'Test Material', + // description: 'Test Description', + // file_path: '/path/to/file.pdf', + // }; + + // const createdMaterial = new Material(createMaterialDto); + // const saveSpy = jest.spyOn(createdMaterial, 'save').mockResolvedValue(createdMaterial); + + // jest.spyOn(model as any, 'new').mockReturnValue(createdMaterial); + + // const result = await service.create(createMaterialDto); + + // expect(model.prototype.save).toHaveBeenCalled(); + // expect(result).toEqual(createdMaterial); + // saveSpy.mockRestore(); + // }); + // }); + + describe('findOne', () => { + it('should call the findById method and return the material', async () => { + const id = 'test-id'; + const foundMaterial = { + _id: id, + type: true, + workspace_id: 'workspace-id-1', + lecturer_id: 'lecturer-id-1', + title: 'Test Material', + description: 'Test Description', + file_path: '/path/to/file.pdf', + }; + + jest.spyOn(model, 'findById').mockReturnValue({ + exec: jest.fn().mockResolvedValue(foundMaterial), + } as unknown as Query); // Cast as Query for TypeScript + + const result = await service.findOne(id); + + expect(model.findById).toHaveBeenCalledWith(id); + expect(result).toEqual(foundMaterial); + }); + }); + + describe('findAllByWorkspaceId', () => { + it('should call the find method and return the materials', async () => { + const workspaceId = 'workspace-id-1'; + const foundMaterials = [ + { + _id: 'test-id-1', + type: true, + workspace_id: workspaceId, + lecturer_id: 'lecturer-id-1', + title: 'Material 1', + description: 'Description 1', + file_path: '/path/to/file1.pdf', + }, + { + _id: 'test-id-2', + type: false, + workspace_id: workspaceId, + lecturer_id: 'lecturer-id-2', + title: 'Material 2', + description: 'Description 2', + file_path: '/path/to/file2.pdf', + }, + ]; + + jest.spyOn(model, 'find').mockReturnValue({ + exec: jest.fn().mockResolvedValue(foundMaterials), + } as unknown as Query); // Cast as Query for TypeScript + + const result = await service.findAllByWorkspaceId(workspaceId); + + expect(model.find).toHaveBeenCalledWith({ workspace_id: workspaceId }); + expect(result).toEqual(foundMaterials); + }); + }); + + describe('update', () => { + it('should call the findByIdAndUpdate method and return the updated material', async () => { + const id = 'test-id'; + const updateMaterialDto: UpdateMaterialDto = { + title: 'Updated Material', + description: 'Updated Description', + file_path: '/path/to/updated-file.pdf', + }; + + const updatedMaterial = { + _id: id, + ...updateMaterialDto, + }; + + jest.spyOn(model, 'findByIdAndUpdate').mockReturnValue({ + exec: jest.fn().mockResolvedValue(updatedMaterial), + } as unknown as Query); // Cast as Query for TypeScript + + const result = await service.update(id, updateMaterialDto); + + expect(model.findByIdAndUpdate).toHaveBeenCalledWith( + id, + updateMaterialDto, + { new: true }, + ); + expect(result).toEqual(updatedMaterial); + }); + }); + + describe('delete', () => { + it('should call the findByIdAndDelete method and return a success message', async () => { + const id = 'test-id'; + const deleteResponse = { + message: 'Learning Material deleted successfully.', + }; + + jest.spyOn(model, 'findByIdAndDelete').mockReturnValue({ + exec: jest.fn().mockResolvedValue(deleteResponse), + } as unknown as Query); // Cast as Query for TypeScript + + const result = await service.delete(id); + + expect(model.findByIdAndDelete).toHaveBeenCalledWith(id); + expect(result).toEqual(deleteResponse); + }); + }); +}); diff --git a/src/server/workspace/src/material/material.service.ts b/src/server/workspace/src/material/material.service.ts new file mode 100644 index 00000000..b6e5be4a --- /dev/null +++ b/src/server/workspace/src/material/material.service.ts @@ -0,0 +1,45 @@ +//this will handle all the database querying + +import { Model } from 'mongoose'; +import { Injectable } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; + +import { Material } from '../schemas/material.schema'; + +import { CreateMaterialDto } from './dto/create-material.dto'; +import { UpdateMaterialDto } from './dto/update-material.dto'; +@Injectable() +export class MaterialService { + constructor( + @InjectModel(Material.name) + private materialModel: Model, + ) {} + + async create(createMaterialDto: CreateMaterialDto): Promise { + const createdMaterial = new this.materialModel(createMaterialDto); + + return createdMaterial.save(); + } + + async findOne(id: string): Promise { + return this.materialModel.findById(id).exec(); + } + + async findAllByWorkspaceId(workspaceId: string): Promise { + return this.materialModel.find({ workspace_id: workspaceId }).exec(); + } + + async update( + id: string, + updateMaterialDto: UpdateMaterialDto, + ): Promise { + return this.materialModel + .findByIdAndUpdate(id, updateMaterialDto, { new: true }) + .exec(); + } + + async delete(id: string): Promise<{ message: string }> { + await this.materialModel.findByIdAndDelete(id).exec(); + return { message: 'Learning Material deleted successfully.' }; + } +} diff --git a/src/server/workspace/src/schedule/dto/create-schedule.dto.ts b/src/server/workspace/src/schedule/dto/create-schedule.dto.ts new file mode 100644 index 00000000..cfe5e78c --- /dev/null +++ b/src/server/workspace/src/schedule/dto/create-schedule.dto.ts @@ -0,0 +1,24 @@ +import { IsDateString, IsNotEmpty, IsString } from 'class-validator'; + +export class CreateScheduleDto { + @IsNotEmpty() + @IsDateString() + date: string; + + @IsNotEmpty() + @IsString() + workspace_id: string; + + //this is the lecturer id + @IsNotEmpty() + @IsString() + lecturer_id: string; + + //@isOptional() + @IsString() + description?: string; + + @IsNotEmpty() + @IsString() + topic: string; +} diff --git a/src/server/workspace/src/schedule/dto/update-schedule.dto.ts b/src/server/workspace/src/schedule/dto/update-schedule.dto.ts new file mode 100644 index 00000000..0430d65a --- /dev/null +++ b/src/server/workspace/src/schedule/dto/update-schedule.dto.ts @@ -0,0 +1,15 @@ +import { IsDateString, IsNotEmpty, IsString } from 'class-validator'; + +export class UpdateScheduleDto { + //@IsNotEmpty() + @IsDateString() + date?: string; + + //@isOptional() + @IsString() + description?: string; + + @IsNotEmpty() + @IsString() + topic?: string; +} diff --git a/src/server/workspace/src/schedule/schedule.controller.spec.ts b/src/server/workspace/src/schedule/schedule.controller.spec.ts new file mode 100644 index 00000000..16af234c --- /dev/null +++ b/src/server/workspace/src/schedule/schedule.controller.spec.ts @@ -0,0 +1,109 @@ +// schedule.controller.spec.ts +import { Test, TestingModule } from '@nestjs/testing'; +import { ScheduleController } from './schedule.controller'; +import { ScheduleService } from './schedule.service'; +//import { CreateScheduleDto } from './dto/create-schedule.dto'; +import { UpdateScheduleDto } from './dto/update-schedule.dto'; +//import { Schedule } from '../schemas/schedule.schema'; + +describe('ScheduleController', () => { + let controller: ScheduleController; + let service: ScheduleService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [ScheduleController], + providers: [ + { + provide: ScheduleService, + useValue: { + //create: jest.fn(), + findOne: jest.fn(), + findAllByWorkspaceId: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + }, + }, + ], + }).compile(); + + controller = module.get(ScheduleController); + service = module.get(ScheduleService); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); + +// describe('create', () => { +// it('should create a new schedule', async () => { +// const createDto: CreateScheduleDto = { +// date: '2024-06-24T10:00:00Z', +// workspace_id: 'workspace-id-1', +// lecturer_id: 'lecturer-id-1', +// description: 'Sample description', +// topic: 'Sample topic', +// }; + +// const createdSchedule: Schedule = { +// _id: '6037bce2df95b73e28bc7227', +// ...createDto, +// }; + +// jest.spyOn(scheduleService, 'create').mockResolvedValue(createdSchedule); + +// const result = await controller.create(createDto); + +// expect(result).toEqual(createdSchedule); +// }); +// }); + +describe('findOne', () => { + it('should call the findOne method of the service', async () => { + const id = 'test-id'; + + await controller.findOne(id); + + expect(service.findOne).toHaveBeenCalledWith(id); + }); +}); + +describe('findAllByWorkspaceId', () => { + it('should call the findAllByWorkspaceId method of the service', async () => { + const workspaceId = 'workspace-id-1'; + + await controller.findAllByWorkspaceId(workspaceId); + + expect(service.findAllByWorkspaceId).toHaveBeenCalledWith(workspaceId); + }); +}); + +describe('update', () => { + it('should call the update method of the service', async () => { + const id = 'test-id'; + const updateScheduleDto: UpdateScheduleDto = { + topic: 'Updated Material', + description: 'Updated Description', + date: '/path/to/updated-file.pdf', + }; + + await controller.update(id, updateScheduleDto); + + expect(service.update).toHaveBeenCalledWith(id, updateScheduleDto); + }); +}); + +describe('delete', () => { + it('should call the delete method of the service', async () => { + const id = 'test-id'; + + await controller.delete(id); + + expect(service.delete).toHaveBeenCalledWith(id); + }); +}); +}); diff --git a/src/server/workspace/src/schedule/schedule.controller.ts b/src/server/workspace/src/schedule/schedule.controller.ts new file mode 100644 index 00000000..664e3a51 --- /dev/null +++ b/src/server/workspace/src/schedule/schedule.controller.ts @@ -0,0 +1,51 @@ +//this will handle all the http reqs and the responses + +import { + Get, + Put, + Body, + Post, + Param, + Delete, + Controller, +} from '@nestjs/common'; + +import { ScheduleService } from './schedule.service'; +import { CreateScheduleDto } from './dto/create-schedule.dto'; +import { UpdateScheduleDto } from './dto/update-schedule.dto'; +import { Schedule } from '../schemas/schedule.schema'; + +@Controller('schedules') +export class ScheduleController { + constructor(private readonly scheduleService: ScheduleService) {} + + @Post() + async create(@Body() createScheduleDto: CreateScheduleDto) { + return this.scheduleService.create(createScheduleDto); + } + + @Get(':id') + async findOne(@Param('id') id: string) { + return this.scheduleService.findOne(id); + } + + @Get('workspace/:workspaceId') + async findAllByWorkspaceId( + @Param('workspaceId') workspaceId: string, + ): Promise { + return this.scheduleService.findAllByWorkspaceId(workspaceId); + } + + @Put(':id') + async update( + @Param('id') id: string, + @Body() updateScheduleDto: UpdateScheduleDto, + ) { + return this.scheduleService.update(id, updateScheduleDto); + } + + @Delete(':id') + async delete(@Param('id') id: string) { + return this.scheduleService.delete(id); + } +} diff --git a/src/server/workspace/src/schedule/schedule.module.ts b/src/server/workspace/src/schedule/schedule.module.ts new file mode 100644 index 00000000..3b9427d8 --- /dev/null +++ b/src/server/workspace/src/schedule/schedule.module.ts @@ -0,0 +1,20 @@ +//this will encapsulate the functionality and components + +import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; + +import { Schedule, ScheduleSchema } from '../schemas/schedule.schema'; +import { ScheduleService } from './schedule.service'; +import { ScheduleController } from './schedule.controller'; + +@Module({ + imports: [ + MongooseModule.forFeature([ + { name: Schedule.name, schema: ScheduleSchema }, + ]), + ], + providers: [ScheduleService], + controllers: [ScheduleController], + exports: [ScheduleService], +}) +export class ScheduleModule {} diff --git a/src/server/workspace/src/schedule/schedule.service.spec.ts b/src/server/workspace/src/schedule/schedule.service.spec.ts new file mode 100644 index 00000000..440e3555 --- /dev/null +++ b/src/server/workspace/src/schedule/schedule.service.spec.ts @@ -0,0 +1,166 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ScheduleService } from './schedule.service'; +import { getModelToken } from '@nestjs/mongoose'; +import { Model, Query } from 'mongoose'; +import { Schedule } from '../schemas/schedule.schema'; +import { UpdateScheduleDto } from './dto/update-schedule.dto'; + +describe('ScheduleService', () => { + let service: ScheduleService; + let model: Model; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ScheduleService, + { + provide: getModelToken(Schedule.name), + useValue: { + new: jest.fn(), + constructor: jest.fn(), + find: jest.fn(), + findOne: jest.fn(), + findById: jest.fn(), + update: jest.fn(), + findByIdAndUpdate: jest.fn(), + findByIdAndDelete: jest.fn(), + exec: jest.fn(), + save: jest.fn(), + }, + }, + ], + }).compile(); + + service = module.get(ScheduleService); + model = module.get>(getModelToken(Schedule.name)); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + // describe('create', () => { + // it('should create a schedule', async () => { + // const createScheduleDto: CreateScheduleDto = { + // topic: 'Test Schedule', // Updated to 'topic' + // description: 'This is a test schedule', + // startTime: new Date('2024-06-24T10:00:00Z'), + // endTime: new Date('2024-06-24T12:00:00Z'), + // workspace_id: 'workspace-id-1', // Use string instead of ObjectId + // }; + + // const createdSchedule: Schedule = { + // _id: 'dummy-id', // Replace with a mock ID + // ...createScheduleDto, + // }; + + // jest.spyOn(model, 'new').mockReturnValue(createdSchedule); + + // const result = await service.create(createScheduleDto); + + // expect(result).toEqual(createdSchedule); + // }); + // }); + + describe('findOne', () => { + it('should find a schedule by id', async () => { + const scheduleId = 'dummy-id'; + + const foundSchedule = { + _id: scheduleId, + topic: 'Found Schedule', // Updated to 'topic' + description: 'This is a found schedule', + date: '2024-06-24T10:00:00Z', + workspace_id: 'workspace-id-1', // Use string instead of ObjectId + }; + + jest.spyOn(model, 'findById').mockReturnValue({ + exec: jest.fn().mockResolvedValue(foundSchedule), + } as unknown as Query); + + const result = await service.findOne(scheduleId); + + expect(model.findById).toHaveBeenCalledWith(scheduleId); + expect(result).toEqual(foundSchedule); + }); + }); + + describe('findAllByWorkspaceId', () => { + it('should call find method and return schedules', async () => { + const workspaceId = 'dummy-workspace-id'; + const foundSchedules = [ + { + _id: 'schedule-id-1', + topic: 'Schedule 1', + description: 'This is schedule 1', + date: '2024-06-26T09:00:00Z', + //endTime: new Date('2024-06-26T11:00:00Z'), + workspace_id: workspaceId, + }, + { + _id: 'schedule-id-2', + topic: 'Schedule 2', + description: 'This is schedule 2', + date: '2024-06-27T09:00:00Z', + //endTime: new Date('2024-06-27T11:00:00Z'), + workspace_id: workspaceId, + }, + ]; + + jest.spyOn(model, 'find').mockReturnValue({ + exec: jest.fn().mockResolvedValue(foundSchedules), + } as any); + + const result = await service.findAllByWorkspaceId(workspaceId); + + expect(model.find).toHaveBeenCalledWith({ workspace_id: workspaceId }); + expect(result).toEqual(foundSchedules); + }); + }); + + describe('update', () => { + it('should call findByIdAndUpdate method and return the updated schedule', async () => { + const id = 'dummy-id'; + const updateScheduleDto: UpdateScheduleDto = { + topic: 'Updated Schedule', + description: 'This is an updated schedule', + date: '2024-06-28T10:00:00Z', + //endTime: new Date('2024-06-28T12:00:00Z'), + //workspace_id: 'workspace-id-1', + }; + const updatedSchedule = { + _id: id, + ...updateScheduleDto, + }; + + jest.spyOn(model, 'findByIdAndUpdate').mockReturnValue({ + exec: jest.fn().mockResolvedValue(updatedSchedule), + } as any); + + const result = await service.update(id, updateScheduleDto); + + expect(model.findByIdAndUpdate).toHaveBeenCalledWith( + id, + updateScheduleDto, + { new: true }, + ); + expect(result).toEqual(updatedSchedule); + }); + }); + + describe('delete', () => { + it('should call findByIdAndDelete method and return a success message', async () => { + const id = 'dummy-id'; + const deleteResponse = { message: 'Lesson deleted successfully.' }; + + jest.spyOn(model, 'findByIdAndDelete').mockReturnValue({ + exec: jest.fn().mockResolvedValue({}), + } as any); + + const result = await service.delete(id); + + expect(model.findByIdAndDelete).toHaveBeenCalledWith(id); + expect(result).toEqual(deleteResponse); + }); + }); +}); diff --git a/src/server/workspace/src/schedule/schedule.service.ts b/src/server/workspace/src/schedule/schedule.service.ts new file mode 100644 index 00000000..46d82fd1 --- /dev/null +++ b/src/server/workspace/src/schedule/schedule.service.ts @@ -0,0 +1,45 @@ +//this will handle all the database querying + +import { Model } from 'mongoose'; +import { Injectable } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; + +import { Schedule } from '../schemas/schedule.schema'; + +import { CreateScheduleDto } from './dto/create-schedule.dto'; +import { UpdateScheduleDto } from './dto/update-schedule.dto'; +@Injectable() +export class ScheduleService { + constructor( + @InjectModel(Schedule.name) + private scheduleModel: Model, + ) {} + + async create(createScheduleDto: CreateScheduleDto): Promise { + const createdSchedule = new this.scheduleModel(createScheduleDto); + + return createdSchedule.save(); + } + + async findOne(id: string): Promise { + return this.scheduleModel.findById(id).exec(); + } + + async findAllByWorkspaceId(workspaceId: string): Promise { + return this.scheduleModel.find({ workspace_id: workspaceId }).exec(); + } + + async update( + id: string, + updateScheduleDto: UpdateScheduleDto, + ): Promise { + return this.scheduleModel + .findByIdAndUpdate(id, updateScheduleDto, { new: true }) + .exec(); + } + + async delete(id: string): Promise<{ message: string }> { + await this.scheduleModel.findByIdAndDelete(id).exec(); + return { message: 'Lesson deleted successfully.' }; + } +} diff --git a/src/server/workspace/src/schemas/material.schema.ts b/src/server/workspace/src/schemas/material.schema.ts new file mode 100644 index 00000000..9cee57b4 --- /dev/null +++ b/src/server/workspace/src/schemas/material.schema.ts @@ -0,0 +1,33 @@ +import { Document, Types } from 'mongoose'; +import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose'; + +//this is the Material schema +@Schema({ timestamps: true }) +export class Material extends Document { + //this is the type + //either 3d model or pdf + @Prop({ required: true }) + type: boolean; + + //this is the workspace id + @Prop({ type: Types.ObjectId, ref: 'Workspace', required: true }) + workspace_id: Types.ObjectId; + + //this is the lecturer id + @Prop({ type: Types.ObjectId, ref: 'User', required: true }) + lecturer_id: Types.ObjectId; + + //this is the title of the material + @Prop({ required: true }) + title: string; + + //this is the description of the material + @Prop({ required: true }) + description: string; + + //this is the filepath of the material + @Prop({ required: true }) + file_path: string; +} + +export const MaterialSchema = SchemaFactory.createForClass(Material); diff --git a/src/server/workspace/src/schemas/schedule.schema.ts b/src/server/workspace/src/schemas/schedule.schema.ts new file mode 100644 index 00000000..9024abd9 --- /dev/null +++ b/src/server/workspace/src/schemas/schedule.schema.ts @@ -0,0 +1,28 @@ +import { Document, Types } from 'mongoose'; +import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose'; + +//this is the Schedule schema +@Schema({ timestamps: true }) +export class Schedule extends Document { + //this is the workspace id + @Prop({ type: Types.ObjectId, ref: 'Workspace', required: true }) + workspace_id: Types.ObjectId; + + //this is the lecturer id + @Prop({ type: Types.ObjectId, ref: 'User', required: true }) + lecturer_id: Types.ObjectId; + + //this is the title of the lesson + @Prop({ required: true }) + topic: string; + + //this is the description of the lesson + @Prop({ required: false }) + description: string; + + //this is the date of the lesson + @Prop({ required: true }) + date: string; +} + +export const ScheduleSchema = SchemaFactory.createForClass(Schedule); diff --git a/src/server/workspace/src/user/user.controller.ts b/src/server/workspace/src/user/user.controller.ts index 02e188ba..88723d63 100644 --- a/src/server/workspace/src/user/user.controller.ts +++ b/src/server/workspace/src/user/user.controller.ts @@ -28,7 +28,7 @@ export class UserController { @Get() async getUsers(@Query() query: Partial) { - return await this.userService.findMany({...query}); + return await this.userService.findMany({ ...query }); } @Put(':id') diff --git a/src/server/workspace/src/user/user.service.ts b/src/server/workspace/src/user/user.service.ts index cf2f3fe0..d5209cc6 100644 --- a/src/server/workspace/src/user/user.service.ts +++ b/src/server/workspace/src/user/user.service.ts @@ -48,7 +48,10 @@ export class UserService { } async findMany(filter: Partial): Promise { - const users = await this.userModel.find(filter).sort({ createdAt: -1 }).exec(); + const users = await this.userModel + .find(filter) + .sort({ createdAt: -1 }) + .exec(); return users; } diff --git a/src/server/workspace/src/workspace/workspace.controller.ts b/src/server/workspace/src/workspace/workspace.controller.ts index 226a0099..60b30c16 100644 --- a/src/server/workspace/src/workspace/workspace.controller.ts +++ b/src/server/workspace/src/workspace/workspace.controller.ts @@ -11,6 +11,7 @@ import { import { WorkspaceService } from './workspace.service'; import { CreateWorkspaceDto } from './dto/create-workspace.dto'; import { UpdateWorkspaceDto } from './dto/update-workspace.dto'; +import { Workspace } from '../schemas/workspace.schema'; @Controller('workspaces') export class WorkspaceController { @@ -21,6 +22,13 @@ export class WorkspaceController { return this.workspaceService.create(createWorkspaceDto); } + @Get('organisation/:organisationId') + async findAllByOrganisationId( + @Param('organisationId') organisationId: string, + ): Promise { + return this.workspaceService.findAllByOrganisationId(organisationId); + } + @Get(':id') async findOne(@Param('id') id: string) { return this.workspaceService.findOne(id); diff --git a/src/server/workspace/src/workspace/workspace.service.ts b/src/server/workspace/src/workspace/workspace.service.ts index 6c8de902..15749507 100644 --- a/src/server/workspace/src/workspace/workspace.service.ts +++ b/src/server/workspace/src/workspace/workspace.service.ts @@ -22,6 +22,10 @@ export class WorkspaceService { return this.workspaceModel.findById(id).exec(); } + async findAllByOrganisationId(organisationId: string): Promise { + return this.workspaceModel.find({ organisation: organisationId }).exec(); + } + async update( id: string, updateWorkspaceDto: UpdateWorkspaceDto,