Skip to content

Commit

Permalink
basic create user flow with email sending
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeh committed Sep 22, 2024
1 parent 33baa69 commit 01b7b90
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 38 deletions.
9 changes: 8 additions & 1 deletion api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ import { ApiConfigModule } from '@api/modules/config/app-config.module';
import { AuthModule } from '@api/modules/auth/auth.module';
import { NotificationsModule } from '@api/modules/notifications/notifications.module';
import { EventsModule } from '@api/modules/events/events.module';
import { AdminModule } from '@api/modules/admin/admin.module';

@Module({
imports: [ApiConfigModule, AuthModule, NotificationsModule, EventsModule],
imports: [
ApiConfigModule,
AuthModule,
NotificationsModule,
EventsModule,
AdminModule,
],
controllers: [AppController],
providers: [AppService],
})
Expand Down
10 changes: 6 additions & 4 deletions api/src/modules/admin/admin.controller.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { RolesGuard } from '@api/modules/auth/guards/roles.guard';
import { RequiredRoles } from '@api/modules/auth/decorators/roles.decorator';
import { ROLES } from '@api/modules/auth/authorisation/roles.enum';
import { AuthenticationService } from '@api/modules/auth/authentication/authentication.service';
import { CreateUserDto } from '@shared/schemas/users/create-user.schema';
import { Public } from '@api/modules/auth/decorators/is-public.decorator';
import { JwtAuthGuard } from '@api/modules/auth/guards/jwt-auth.guard';
import { ROLES } from '@api/modules/auth/authorisation/roles.enum';
import { RequiredRoles } from '@api/modules/auth/decorators/roles.decorator';

@Controller('admin')
@UseGuards(AuthGuard, RolesGuard)
@UseGuards(JwtAuthGuard, RolesGuard)
export class AdminController {
constructor(private readonly auth: AuthenticationService) {}

@Public()
@RequiredRoles(ROLES.ADMIN)
@Post('/users')
async createUser(@Body() createUserDto: CreateUserDto): Promise<void> {
Expand Down
4 changes: 2 additions & 2 deletions api/src/modules/admin/admin.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Module } from '@nestjs/common';
import { AdminController } from './admin.controller';
import { UsersModule } from '@api/modules/users/users.module';
import { AuthModule } from '@api/modules/auth/auth.module';

@Module({
imports: [UsersModule],
imports: [AuthModule],
controllers: [AdminController],
})
export class AdminModule {}
1 change: 1 addition & 0 deletions api/src/modules/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ import { AuthenticationController } from '@api/modules/auth/authentication/authe
imports: [AuthenticationModule, AuthorisationModule, NotificationsModule],
controllers: [AuthenticationController],
providers: [PasswordRecoveryService, AuthMailer],
exports: [AuthenticationModule, AuthMailer],
})
export class AuthModule {}
29 changes: 22 additions & 7 deletions api/src/modules/auth/authentication/authentication.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { JwtService } from '@nestjs/jwt';
import { UsersService } from '@api/modules/users/users.service';
import { User } from '@shared/entities/users/user.entity';
import * as bcrypt from 'bcrypt';
import { JwtPayload } from '@api/modules/auth/strategies/jwt.strategy';
import { CommandBus, EventBus } from '@nestjs/cqrs';
import { UserSignedUpEvent } from '@api/modules/events/user-events/user-signed-up.event';
import { UserWithAccessToken } from '@shared/dtos/user.dto';
import { TOKEN_TYPE_ENUM } from '@shared/schemas/auth/token-type.schema';
import { ApiConfigService } from '@api/modules/config/app-config.service';
Expand Down Expand Up @@ -42,14 +40,16 @@ export class AuthenticationService {
partnerName,
isActive: false,
});
void this.commandBus.execute(
new SendWelcomeEmailCommand(newUser, plainTextPassword),
);
await this.commandBus
.execute(new SendWelcomeEmailCommand(newUser, plainTextPassword))
.catch(() => this.usersService.delete(newUser));
}

async logIn(user: User): Promise<UserWithAccessToken> {
const payload: JwtPayload = { id: user.id };
const accessToken: string = this.jwt.sign(payload);
const { token: accessToken } = await this.signTokenByType(
TOKEN_TYPE_ENUM.ACCESS,
user.id,
);
return { user, accessToken };
}

Expand All @@ -62,4 +62,19 @@ export class AuthenticationService {
throw new UnauthorizedException();
}
}

private async signTokenByType(
tokenType: TOKEN_TYPE_ENUM,
userId: string,
): Promise<{ token: string; expiresIn: string }> {
const { secret, expiresIn } = this.apiConfig.getJWTConfigByType(tokenType);
const token = await this.jwt.signAsync(
{ id: userId },
{
secret,
expiresIn,
},
);
return { token, expiresIn };
}
}
6 changes: 5 additions & 1 deletion api/src/modules/notifications/email/email.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { Module } from '@nestjs/common';
import { forwardRef, Module } from '@nestjs/common';
import { IEmailServiceToken } from '@api/modules/notifications/email/email-service.interface';
import { NodemailerEmailService } from '@api/modules/notifications/email/nodemailer.email.service';
import { SendWelcomeEmailHandler } from '@api/modules/notifications/email/commands/send-welcome-email.handler';
import { AuthModule } from '@api/modules/auth/auth.module';

@Module({
imports: [forwardRef(() => AuthModule)],
providers: [
{ provide: IEmailServiceToken, useClass: NodemailerEmailService },
SendWelcomeEmailHandler,
],
exports: [IEmailServiceToken],
})
Expand Down
24 changes: 1 addition & 23 deletions api/src/modules/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,4 @@
import { Controller, Get } from '@nestjs/common';
import { RequiredRoles } from '@api/modules/auth/decorators/roles.decorator';
import { ROLES } from '@api/modules/auth/authorisation/roles.enum';

@Controller('users')
export class UsersController {
// TODO: All of these endpoints are fake, only to test the role guard

@RequiredRoles(ROLES.ADMIN)
@Get('admin')
async createUserAsAdmin() {
return [ROLES.ADMIN];
}

@RequiredRoles(ROLES.PARTNER)
@Get('partner')
async createUserAsPartner() {
return [ROLES.PARTNER, ROLES.ADMIN];
}

@RequiredRoles(ROLES.GENERAL_USER)
@Get('user')
async createUserAsUser() {
return [ROLES.GENERAL_USER, ROLES.PARTNER, ROLES.ADMIN];
}
}
export class UsersController {}
4 changes: 4 additions & 0 deletions api/src/modules/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ export class UsersService {
user.password = newPassword;
return this.repo.save(user);
}

async delete(user: User) {
return this.repo.remove(user);
}
}

0 comments on commit 01b7b90

Please sign in to comment.