Skip to content

Commit

Permalink
Merge branch 'develop' into dependabot/github_actions/actions/github-…
Browse files Browse the repository at this point in the history
…script-7
  • Loading branch information
annarhughes committed Jun 17, 2024
2 parents 2c55acb + ceeb76a commit 9cf7737
Show file tree
Hide file tree
Showing 21 changed files with 269 additions and 82 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@
},
"dependencies": {
"@mailchimp/mailchimp_marketing": "^3.0.80",
"@nestjs/axios": "^3.0.2",
"@nestjs/common": "^10.3.6",
"@nestjs/config": "^3.2.2",
"@nestjs/core": "^10.3.6",
"@nestjs/platform-express": "^10.3.7",
"@nestjs/swagger": "^7.3.1",
"@nestjs/terminus": "^10.2.3",
"@nestjs/typeorm": "^10.0.2",
"axios": "^1.6.8",
"axios": "^1.7.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"date-fns": "^3.6.0",
Expand Down
22 changes: 0 additions & 22 deletions src/app.controller.spec.ts

This file was deleted.

9 changes: 0 additions & 9 deletions src/app.controller.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { AuthModule } from './auth/auth.module';
import { CoursePartnerModule } from './course-partner/course-partner.module';
import { CourseUserModule } from './course-user/course-user.module';
import { CourseModule } from './course/course.module';
import { EventLoggerModule } from './event-logger/event-logger.module';
import { FeatureModule } from './feature/feature.module';
import { HealthModule } from './health/health.module';
import { LoggerModule } from './logger/logger.module';
import { PartnerAccessModule } from './partner-access/partner-access.module';
import { PartnerAdminModule } from './partner-admin/partner-admin.module';
Expand Down Expand Up @@ -37,6 +39,8 @@ import { WebhooksModule } from './webhooks/webhooks.module';
SubscriptionUserModule,
FeatureModule,
PartnerFeatureModule,
EventLoggerModule,
HealthModule,
],
})
export class AppModule {}
31 changes: 12 additions & 19 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import {
} from '@nestjs/common';
import { DecodedIdToken } from 'firebase-admin/lib/auth/token-verifier';
import { Logger } from 'src/logger/logger';
import {
CREATE_USER_FIREBASE_ERROR,
CREATE_USER_INVALID_EMAIL,
CREATE_USER_WEAK_PASSWORD,
} from 'src/utils/errors';
import { FIREBASE_ERRORS } from 'src/utils/errors';
import { FIREBASE } from '../firebase/firebase-factory';
import { FirebaseServices } from '../firebase/firebase.types';
import { UserAuthDto } from './dto/user-auth.dto';
Expand Down Expand Up @@ -55,27 +51,24 @@ export class AuthService {
return firebaseUser;
} catch (err) {
const errorCode = err.code;

if (errorCode === 'auth/invalid-email') {
this.logger.warn(
`Create user: user tried to create email with invalid email: ${email} - ${err}`,
);
throw new HttpException(CREATE_USER_INVALID_EMAIL, HttpStatus.BAD_REQUEST);
}
if (
errorCode === 'auth/weak-password' ||
err.message.includes('The password must be a string with at least 6 characters')
) {
throw new HttpException(FIREBASE_ERRORS.CREATE_USER_INVALID_EMAIL, HttpStatus.BAD_REQUEST);
} else if (errorCode === 'auth/weak-password' || errorCode === 'auth/invalid-password') {
this.logger.warn(`Create user: user tried to create email with weak password - ${err}`);
throw new HttpException(CREATE_USER_WEAK_PASSWORD, HttpStatus.BAD_REQUEST);
}
if (errorCode === 'auth/email-already-in-use' && errorCode === 'auth/email-already-exists') {
this.logger.log(
`Create user: Firebase user already exists so fetching firebase user: ${email}`,
);
return await this.getFirebaseUser(email);
throw new HttpException(FIREBASE_ERRORS.CREATE_USER_WEAK_PASSWORD, HttpStatus.BAD_REQUEST);
} else if (
errorCode === 'auth/email-already-in-use' ||
errorCode === 'auth/email-already-exists'
) {
this.logger.warn(`Create user: Firebase user already exists: ${email}`);
throw new HttpException(FIREBASE_ERRORS.CREATE_USER_ALREADY_EXISTS, HttpStatus.BAD_REQUEST);
} else {
this.logger.error(`Create user: Error creating firebase user - ${email}: ${err}`);
throw new HttpException(CREATE_USER_FIREBASE_ERROR, HttpStatus.BAD_REQUEST);
throw new HttpException(FIREBASE_ERRORS.CREATE_USER_FIREBASE_ERROR, HttpStatus.BAD_REQUEST);
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/event-logger/event-logger.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Body, Controller, Post, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { FirebaseAuthGuard } from 'src/firebase/firebase-auth.guard';
import { ControllerDecorator } from 'src/utils/controller.decorator';
import { EVENT_NAME } from './event-logger.interface';
import { EventLoggerService } from './event-logger.service';

@ApiTags('Event Logger')
@ControllerDecorator()
@Controller('/v1/event-logger')
export class EventLoggerController {
constructor(private readonly eventLoggerService: EventLoggerService) {}

@Post()
@ApiOperation({
description: 'Creates an event log',
})
@ApiBearerAuth('access-token')
@UseGuards(FirebaseAuthGuard)
async createEventLog(@Req() req: Request, @Body() { event }: { event: EVENT_NAME }) {
const now = new Date();
return await this.eventLoggerService.createEventLog({
userId: req['userEntity'].id,
event,
date: now,
});
}
}
2 changes: 2 additions & 0 deletions src/event-logger/event-logger.interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export enum EVENT_NAME {
CHAT_MESSAGE_SENT = 'CHAT_MESSAGE_SENT',
LOGGED_IN = 'LOGGED_IN',
LOGGED_OUT = 'LOGGED_OUT',
}

export interface ICreateEventLog {
Expand Down
40 changes: 37 additions & 3 deletions src/event-logger/event-logger.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,44 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SlackMessageClient } from 'src/api/slack/slack-api';
import { ZapierWebhookClient } from 'src/api/zapier/zapier-webhook-client';
import { EventLogEntity } from 'src/entities/event-log.entity';
import { PartnerAccessEntity } from 'src/entities/partner-access.entity';
import { PartnerEntity } from 'src/entities/partner.entity';
import { SubscriptionUserEntity } from 'src/entities/subscription-user.entity';
import { SubscriptionEntity } from 'src/entities/subscription.entity';
import { TherapySessionEntity } from 'src/entities/therapy-session.entity';
import { UserEntity } from 'src/entities/user.entity';
import { PartnerAccessService } from 'src/partner-access/partner-access.service';
import { SubscriptionUserService } from 'src/subscription-user/subscription-user.service';
import { SubscriptionService } from 'src/subscription/subscription.service';
import { TherapySessionService } from 'src/therapy-session/therapy-session.service';
import { UserService } from 'src/user/user.service';
import { EventLoggerController } from './event-logger.controller';
import { EventLoggerService } from './event-logger.service';

@Module({
imports: [TypeOrmModule.forFeature([EventLogEntity])],
providers: [EventLoggerService],
imports: [
TypeOrmModule.forFeature([
EventLogEntity,
UserEntity,
PartnerAccessEntity,
PartnerEntity,
SubscriptionUserEntity,
TherapySessionEntity,
SubscriptionEntity,
]),
],
controllers: [EventLoggerController],
providers: [
EventLoggerService,
UserService,
SubscriptionUserService,
TherapySessionService,
PartnerAccessService,
SubscriptionService,
ZapierWebhookClient,
SlackMessageClient,
],
})
export class SessionModule {}
export class EventLoggerModule {}
21 changes: 21 additions & 0 deletions src/health/health.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { HttpModule } from '@nestjs/axios';
import { TerminusModule } from '@nestjs/terminus';
import { Test, TestingModule } from '@nestjs/testing';
import { HealthController } from './health.controller';

describe('HealthController', () => {
let controller: HealthController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [TerminusModule, HttpModule],
controllers: [HealthController],
}).compile();

controller = module.get<HealthController>(HealthController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
35 changes: 35 additions & 0 deletions src/health/health.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Controller, Get } from '@nestjs/common';
import {
HealthCheck,
HealthCheckService,
HttpHealthIndicator,
TypeOrmHealthIndicator,
} from '@nestjs/terminus';
import { frontendAppUrl } from 'src/utils/constants';

@Controller('ping')
export class HealthController {
constructor(
private readonly health: HealthCheckService,
private readonly http: HttpHealthIndicator,
private readonly db: TypeOrmHealthIndicator,
) {}

@Get()
@HealthCheck()
ping() {
return 'ok';
}

@Get('/frontend')
@HealthCheck()
checkFrontend() {
return this.health.check([() => this.http.pingCheck('frontend', frontendAppUrl)]);
}

@Get('/database')
@HealthCheck()
checkDatabase() {
return this.health.check([() => this.db.pingCheck('database')]);
}
}
10 changes: 10 additions & 0 deletions src/health/health.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';

@Module({
imports: [TerminusModule, HttpModule],
controllers: [HealthController],
})
export class HealthModule {}
2 changes: 2 additions & 0 deletions src/logger/logger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ConsoleLogger } from '@nestjs/common';
import Rollbar from 'rollbar';
import { FIREBASE_ERRORS } from 'src/utils/errors';
import { isProduction, rollbarEnv, rollbarToken } from '../utils/constants';

export class Logger extends ConsoleLogger {
Expand Down Expand Up @@ -36,6 +37,7 @@ export class Logger extends ConsoleLogger {
accessToken: rollbarToken,
captureUncaught: true,
captureUnhandledRejections: true,
ignoredMessages: [...Object.values(FIREBASE_ERRORS)],
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ async function bootstrap() {

app.setGlobalPrefix('api');

// Starts listening for shutdown hooks
app.enableShutdownHooks();

const options = new DocumentBuilder()
.setTitle('Bloom backend API')
.setDescription('Bloom backend API')
Expand Down
7 changes: 4 additions & 3 deletions src/partner-access/partner-access.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ describe('PartnerAccessService', () => {
let mockPartnerAccessRepository: DeepMocked<Repository<PartnerAccessEntity>>;

beforeEach(async () => {
jest.clearAllMocks();

mockPartnerRepository = createMock<Repository<PartnerEntity>>(mockPartnerRepositoryMethods);
mockPartnerAccessRepository = createMock<Repository<PartnerAccessEntity>>(
mockPartnerAccessRepositoryMethods,
Expand Down Expand Up @@ -136,7 +138,7 @@ describe('PartnerAccessService', () => {
return {
...mockPartnerAccessEntity,
id: 'pa1',
userId: mockGetUserDto.user.id,
userId: mockUserEntity.id,
};
});
// Mocks that the accesscode already exists
Expand All @@ -146,13 +148,12 @@ describe('PartnerAccessService', () => {

expect(partnerAccess).toEqual({
...mockPartnerAccessEntity,
id: 'pa1',
userId: mockUserEntity.id,
activatedAt: partnerAccess.activatedAt,
});

expect(profileData.updateServiceUserProfilesPartnerAccess).toHaveBeenCalledWith(
[partnerAccess],
[mockPartnerAccessEntity],
mockUserEntity.email,
);
});
Expand Down
9 changes: 6 additions & 3 deletions src/partner-access/partner-access.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,12 @@ export class PartnerAccessService {
assignedPartnerAccess.partner = partnerAccess.partner;

try {
const partnerAccesses = await this.partnerAccessRepository.findBy({
userId: user.id,
active: true,
const partnerAccesses = await this.partnerAccessRepository.find({
where: {
userId: user.id,
active: true,
},
relations: { partner: true },
});
updateServiceUserProfilesPartnerAccess(partnerAccesses, user.email);
} catch (error) {
Expand Down
15 changes: 12 additions & 3 deletions src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { Logger } from 'src/logger/logger';
import { SubscriptionUserService } from 'src/subscription-user/subscription-user.service';
import { TherapySessionService } from 'src/therapy-session/therapy-session.service';
import { SIGNUP_TYPE } from 'src/utils/constants';
import { FIREBASE_ERRORS } from 'src/utils/errors';
import {
createServiceUserProfiles,
updateServiceUserProfilesUser,
} from 'src/utils/serviceUserProfiles';
import { And, ILike, Raw, Repository } from 'typeorm';
import { And, ILike, IsNull, Not, Raw, Repository } from 'typeorm';
import { deleteCypressCrispProfiles } from '../api/crisp/crisp-api';
import { AuthService } from '../auth/auth.service';
import { PartnerAccessService, basePartnerAccess } from '../partner-access/partner-access.service';
Expand Down Expand Up @@ -63,6 +64,7 @@ export class UserService {
}

const firebaseUser = await this.authService.createFirebaseUser(email, password);

const user = await this.userRepository.save({
...createUserDto,
firebaseUid: firebaseUser.uid,
Expand Down Expand Up @@ -97,7 +99,9 @@ export class UserService {
});
return userDto;
} catch (error) {
this.logger.error(`Create user: Error creating user ${email}: ${error}`);
if (!Object.values(FIREBASE_ERRORS).includes(error)) {
this.logger.error(`Create user: Error creating user ${email}: ${error}`);
}
throw error;
}
}
Expand Down Expand Up @@ -289,7 +293,12 @@ export class UserService {
}),
...(filters.partnerAdmin && {
partnerAdmin: {
...(filters.partnerAdmin && { id: filters.partnerAdmin.partnerAdminId }),
...(filters.partnerAdmin && {
id:
filters.partnerAdmin.partnerAdminId === 'IS NOT NULL'
? Not(IsNull())
: filters.partnerAdmin.partnerAdminId,
}),
},
}),
},
Expand Down
Loading

0 comments on commit 9cf7737

Please sign in to comment.