Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore(maintenance)/refactor get user profile subscriptions #430 #710

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion src/partner/dtos/update-partner.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export class UpdatePartnerDto {
@IsBoolean()
@ApiProperty({ type: Boolean })
active: boolean;
}
}
5 changes: 1 addition & 4 deletions src/partner/partner.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
36 changes: 15 additions & 21 deletions src/partner/partner.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ describe('PartnerService', () => {
let mockUserRepository: DeepMocked<Repository<UserEntity>>;

beforeEach(async () => {
mockPartnerRepository = createMock<Repository<PartnerEntity>>(
mockPartnerRepositoryMethods,
);
mockPartnerRepository = createMock<Repository<PartnerEntity>>(mockPartnerRepositoryMethods);
mockPartnerAccessRepository = createMock<Repository<PartnerAccessEntity>>();
mockPartnerAdminRepository = createMock<Repository<PartnerAdminEntity>>();
mockUserRepository = createMock<Repository<UserEntity>>();
Expand All @@ -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');
})
})
});
await expect(service.updatePartner(mockPartnerEntity.id, { active: false })).rejects.toThrow(
'Error unable to update',
);
});
});
});
2 changes: 1 addition & 1 deletion src/partner/partner.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/session-user/session-user.controller.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
2 changes: 1 addition & 1 deletion src/session-user/session-user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class SessionUserService {
}

public async setSessionUserCompleted(
user : UserEntity,
user: UserEntity,
{ storyblokId }: UpdateSessionUserDto,
completed: boolean,
) {
Expand Down
3 changes: 0 additions & 3 deletions src/subscription/subscription.interface.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/user/dtos/get-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -11,5 +10,4 @@ export class GetUserDto {
partnerAdmin?: IPartnerAdminWithPartner;
courses?: ICoursesWithSessions[];
therapySessions?: ITherapySession[];
subscriptions?: ISubscriptionUser[];
}
69 changes: 69 additions & 0 deletions src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '[email protected]';
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: '[email protected]',
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 () => {
Expand Down
2 changes: 0 additions & 2 deletions src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
10 changes: 0 additions & 10 deletions src/utils/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
: [],
};
};

Expand Down Expand Up @@ -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 => {
Expand Down