diff --git a/docker-compose.yml b/docker-compose.yml index 23f15ae9..8b930207 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,12 +2,14 @@ version: '3.9' services: api: + env_file: + - .env container_name: bloom-backend build: context: . dockerfile: Dockerfile environment: - DATABASE_URL: postgres://postgres:postgres@host.docker.internal:35000/bloom + DATABASE_URL: postgres://postgres:postgres@db:5432/bloom ports: - 35001:35001 depends_on: diff --git a/src/partner/dtos/update-partner.dto.ts b/src/partner/dtos/update-partner.dto.ts index 3f5634f3..86b6006a 100644 --- a/src/partner/dtos/update-partner.dto.ts +++ b/src/partner/dtos/update-partner.dto.ts @@ -5,4 +5,4 @@ export class UpdatePartnerDto { @IsBoolean() @ApiProperty({ type: Boolean }) active: boolean; -} \ No newline at end of file +} diff --git a/src/partner/partner.controller.ts b/src/partner/partner.controller.ts index d3bafd3e..96fab99c 100644 --- a/src/partner/partner.controller.ts +++ b/src/partner/partner.controller.ts @@ -49,10 +49,7 @@ export class PartnerController { @Patch(':id') @ApiOperation({ description: 'Update a partner profile and makes partner active or inactive' }) @ApiBody({ type: UpdatePartnerDto }) - async updatePartner( - @Param() { id }, - @Body() updatePartnerDto: UpdatePartnerDto, - ) { + async updatePartner(@Param() { id }, @Body() updatePartnerDto: UpdatePartnerDto) { return this.partnerService.updatePartner(id, updatePartnerDto); } } diff --git a/src/partner/partner.service.spec.ts b/src/partner/partner.service.spec.ts index e76f454d..c694538d 100644 --- a/src/partner/partner.service.spec.ts +++ b/src/partner/partner.service.spec.ts @@ -22,9 +22,7 @@ describe('PartnerService', () => { let mockUserRepository: DeepMocked>; beforeEach(async () => { - mockPartnerRepository = createMock>( - mockPartnerRepositoryMethods, - ); + mockPartnerRepository = createMock>(mockPartnerRepositoryMethods); mockPartnerAccessRepository = createMock>(); mockPartnerAdminRepository = createMock>(); mockUserRepository = createMock>(); @@ -50,39 +48,35 @@ describe('PartnerService', () => { it('when supplied with correct data should return new partner', async () => { const response = await service.createPartner(createPartnerDto); expect(response).toMatchObject(createPartnerDto); - }) + }); it('when supplied with a name that already exists, it should throw error', async () => { - jest - .spyOn(mockPartnerRepository, 'create') - .mockImplementationOnce(() => { - throw ({ code: '23505' }); - }); + jest.spyOn(mockPartnerRepository, 'create').mockImplementationOnce(() => { + throw { code: '23505' }; + }); await expect(service.createPartner(createPartnerDto)).rejects.toThrow(); - }) + }); }); describe('updatePartner', () => { it('when supplied with correct data should return new partner', async () => { jest.spyOn(mockPartnerRepository, 'createQueryBuilder').mockImplementationOnce( createQueryBuilderMock({ - execute: jest - .fn() - .mockResolvedValue({raw: [{ ...mockPartnerEntity, active: false }]}) + execute: jest.fn().mockResolvedValue({ raw: [{ ...mockPartnerEntity, active: false }] }), }) as never, // TODO resolve this typescript issue ); const response = await service.updatePartner(mockPartnerEntity.id, { active: false }); expect(response).toMatchObject({ ...mockPartnerEntity, active: false }); - }) + }); it('when supplied with incorrect partnerName should throw', async () => { jest.spyOn(mockPartnerRepository, 'createQueryBuilder').mockImplementationOnce(() => { throw new Error('Error unable to update'); - }) + }); - await expect( - service.updatePartner(mockPartnerEntity.id, { active: false }) - ).rejects.toThrow('Error unable to update'); - }) - }) -}); \ No newline at end of file + await expect(service.updatePartner(mockPartnerEntity.id, { active: false })).rejects.toThrow( + 'Error unable to update', + ); + }); + }); +}); diff --git a/src/partner/partner.service.ts b/src/partner/partner.service.ts index 5555cc9b..d4c400de 100644 --- a/src/partner/partner.service.ts +++ b/src/partner/partner.service.ts @@ -92,7 +92,7 @@ export class PartnerService { return 'Successful'; } - async updatePartner(partnerId: string, { active }: UpdatePartnerDto){ + async updatePartner(partnerId: string, { active }: UpdatePartnerDto) { const updatedPartnerResponse = await this.partnerRepository .createQueryBuilder() .update(PartnerEntity) diff --git a/src/session-user/session-user.controller.ts b/src/session-user/session-user.controller.ts index 8ea52d1f..18834159 100644 --- a/src/session-user/session-user.controller.ts +++ b/src/session-user/session-user.controller.ts @@ -1,7 +1,7 @@ import { Body, Controller, Post, Req, UseGuards } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { Request } from 'express'; -import {UserEntity} from '../entities/user.entity'; +import { UserEntity } from '../entities/user.entity'; import { ControllerDecorator } from 'src/utils/controller.decorator'; import { FirebaseAuthGuard } from '../firebase/firebase-auth.guard'; import { UpdateSessionUserDto } from './dtos/update-session-user.dto'; diff --git a/src/session-user/session-user.service.ts b/src/session-user/session-user.service.ts index 70f5385a..869a57de 100644 --- a/src/session-user/session-user.service.ts +++ b/src/session-user/session-user.service.ts @@ -131,7 +131,7 @@ export class SessionUserService { } public async setSessionUserCompleted( - user : UserEntity, + user: UserEntity, { storyblokId }: UpdateSessionUserDto, completed: boolean, ) { diff --git a/src/subscription/subscription.interface.ts b/src/subscription/subscription.interface.ts deleted file mode 100644 index ff3d4128..00000000 --- a/src/subscription/subscription.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ISubscription { - name?: string; -} diff --git a/src/user/dtos/get-user.dto.ts b/src/user/dtos/get-user.dto.ts index 24bee062..b122638e 100644 --- a/src/user/dtos/get-user.dto.ts +++ b/src/user/dtos/get-user.dto.ts @@ -2,7 +2,6 @@ import { ICoursesWithSessions } from 'src/course/course.interface'; import { ITherapySession } from 'src/webhooks/therapy-session.interface'; import { IPartnerAccessWithPartner } from '../../partner-access/partner-access.interface'; import { IPartnerAdminWithPartner } from '../../partner-admin/partner-admin.interface'; -import { ISubscriptionUser } from '../../subscription-user/subscription-user.interface'; import { IUser } from '../user.interface'; export class GetUserDto { @@ -11,5 +10,4 @@ export class GetUserDto { partnerAdmin?: IPartnerAdminWithPartner; courses?: ICoursesWithSessions[]; therapySessions?: ITherapySession[]; - subscriptions?: ISubscriptionUser[]; } diff --git a/src/user/user.service.spec.ts b/src/user/user.service.spec.ts index 63cce7b9..7ff038d7 100644 --- a/src/user/user.service.spec.ts +++ b/src/user/user.service.spec.ts @@ -547,6 +547,75 @@ describe('UserService', () => { }); }); + describe('getUserProfile', () => { + it('should return user entity and user DTO when user is found', async () => { + const mockUserEntity = new UserEntity(); + mockUserEntity.id = 'userId1'; + mockUserEntity.email = 'user@email.com'; + mockUserEntity.name = 'name'; + mockUserEntity.createdAt = new Date('2024-11-19T19:18:51.796Z'); + mockUserEntity.updatedAt = new Date('2024-11-19T19:18:51.796Z'); + mockUserEntity.lastActiveAt = new Date('2024-11-19T19:18:51.796Z'); + mockUserEntity.isActive = true; + mockUserEntity.isSuperAdmin = false; + mockUserEntity.signUpLanguage = 'en'; + mockUserEntity.emailRemindersFrequency = EMAIL_REMINDERS_FREQUENCY.TWO_MONTHS; + mockUserEntity.firebaseUid = '123'; + mockUserEntity.crispTokenId = '123'; + mockUserEntity.serviceEmailsPermission = true; + mockUserEntity.contactPermission = true; + mockUserEntity.deletedAt = null; + mockUserEntity.courseUser = []; + mockUserEntity.partnerAccess = []; + mockUserEntity.partnerAdmin = null; + mockUserEntity.subscriptionUser = []; + mockUserEntity.therapySession = []; + mockUserEntity.eventLog = []; + + const mockUserDto = { + user: { + id: 'userId1', + email: 'user@email.com', + name: 'name', + createdAt: new Date('2024-11-19T19:18:51.796Z'), + updatedAt: new Date('2024-11-19T19:18:51.796Z'), + lastActiveAt: new Date('2024-11-19T19:18:51.796Z'), + isActive: true, + isSuperAdmin: false, + signUpLanguage: 'en', + emailRemindersFrequency: 'TWO_MONTHS', + firebaseUid: '123', + crispTokenId: '123', + deletedAt: null, + }, + partnerAccesses: [], + partnerAdmin: null, + courses: [], + }; + + jest.spyOn(repo, 'createQueryBuilder').mockReturnValue({ + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + getOne: jest.fn().mockResolvedValue(mockUserEntity), + } as any); + + const result = await service.getUserProfile('userId1'); + expect(result).toEqual({ userEntity: mockUserEntity, userDto: mockUserDto }); + }); + + it('should throw HttpException when user is not found', async () => { + jest.spyOn(repo, 'createQueryBuilder').mockReturnValue({ + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + getOne: jest.fn().mockResolvedValue(undefined), + } as any); + + await expect(service.getUserProfile('userId1')).rejects.toThrow( + new HttpException('USER NOT FOUND', HttpStatus.NOT_FOUND), + ); + }); +}); + // TODO - Extend getUser tests. At the moment, this is only used by super admins describe('getUsers', () => { it('getUsers', async () => { diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 41e184ff..387d4378 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -139,8 +139,6 @@ export class UserService { .leftJoinAndSelect('courseUser.course', 'course') .leftJoinAndSelect('courseUser.sessionUser', 'sessionUser') .leftJoinAndSelect('sessionUser.session', 'session') - .leftJoinAndSelect('user.subscriptionUser', 'subscriptionUser') - .leftJoinAndSelect('subscriptionUser.subscription', 'subscription') .where('user.id = :id', { id }) .getOne(); diff --git a/src/utils/serialize.ts b/src/utils/serialize.ts index a97e4dc8..971c9e30 100644 --- a/src/utils/serialize.ts +++ b/src/utils/serialize.ts @@ -113,10 +113,6 @@ export const formatUserObject = (userObject: UserEntity): GetUserDto => { ? formatPartnerAdminObjects(userObject.partnerAdmin) : null, courses: userObject.courseUser ? formatCourseUserObjects(userObject.courseUser) : [], - subscriptions: - userObject.subscriptionUser && userObject.subscriptionUser.length > 0 - ? formatSubscriptionObjects(userObject.subscriptionUser) - : [], }; }; @@ -188,12 +184,6 @@ export const serializeZapierSimplyBookDtoToTherapySessionEntity = ( }; }; -export const formatSubscriptionObjects = ( - userSubscriptions: SubscriptionUserEntity[], -): ISubscriptionUser[] => { - return userSubscriptions.map((userSubscription) => formatSubscriptionObject(userSubscription)); -}; - export const formatSubscriptionObject = ( userSubscription: SubscriptionUserEntity, ): ISubscriptionUser => {