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

feat: create user endpoint #77

Merged
merged 7 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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: 4 additions & 0 deletions apps/api/src/mail/services/interface.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@ export interface IMailService {
invitedBy: string,
role: ProjectRole
): Promise<void>

accountLoginEmail(
email: string
): Promise<void>
}
22 changes: 22 additions & 0 deletions apps/api/src/mail/services/mail.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,28 @@ export class MailService implements IMailService {
await this.sendEmail(email, subject, body)
}

async accountLoginEmail(
email: string
): Promise<void> {
const subject = 'LogIn Invitation Accepted'
const body = `<!DOCTYPE html>
<html>
<head>
<title>LogIn Invitaion</title>
</head>
<body>
<h1>Welcome to keyshade!</h1>
<p>Hello there!</p>
<p>Your account has been setup. Please login to your account for further process.</p>
<p>Thank you for choosing us.</p>
<p>Best Regards,</p>
<p>keyshade Team</p>
</body>
</html>
`
await this.sendEmail(email, subject, body)
}

private async sendEmail(
email: string,
subject: string,
Expand Down
4 changes: 4 additions & 0 deletions apps/api/src/mail/services/mock.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ export class MockMailService implements IMailService {
async sendOtp(email: string, otp: string): Promise<void> {
this.log.log(`OTP for ${email} is ${otp}`)
}

async accountLoginEmail(email: string): Promise<void> {
this.log.log(`Account Login Email for ${email}`)
}
}
8 changes: 8 additions & 0 deletions apps/api/src/user/controller/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Controller,
Get,
Param,
Post,
Put,
Query,
UseGuards
Expand All @@ -12,6 +13,7 @@ import { CurrentUser } from '../../decorators/user.decorator'
import { User } from '@prisma/client'
import { UpdateUserDto } from '../dto/update.user/update.user'
import { AdminGuard } from '../../auth/guard/admin.guard'
import { ICreateUserDTO } from '../dto/create.user/create.user'
import { ApiTags } from '@nestjs/swagger'

@ApiTags('User Controller')
Expand Down Expand Up @@ -60,4 +62,10 @@ export class UserController {
) {
return await this.userService.getAllUsers(page, limit, sort, order, search)
}

@Post('')
@UseGuards(AdminGuard)
async createUser(@Body() dto: ICreateUserDTO) {
return await this.userService.createUser(dto);
}
}
16 changes: 16 additions & 0 deletions apps/api/src/user/dto/create.user/create.user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IsBoolean, IsString } from "class-validator";

export class ICreateUserDTO {
rajdip-b marked this conversation as resolved.
Show resolved Hide resolved
@IsString()
name: string;
@IsString()
email: string;
@IsString()
rajdip-b marked this conversation as resolved.
Show resolved Hide resolved
profilePictureUrl: string;
@IsBoolean()
isActive: boolean;
@IsBoolean()
isOnboardingFinished: boolean;
@IsBoolean()
isAdmin: boolean;
}
7 changes: 7 additions & 0 deletions apps/api/src/user/repository/interface.repository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { User } from '@prisma/client'
import { ICreateUserDTO } from '../dto/create.user/create.user'

export const USER_REPOSITORY = 'USER_REPOSITORY'

Expand Down Expand Up @@ -58,4 +59,10 @@ export interface IUserRepository {
* @returns {Promise<User>} - A promise that resolves to the deleted user.
*/
deleteUser(id: string): Promise<User>

/**
* Create user by admin
* @returns {Promise<number>} - A promise that resolves to create user.
*/
createUserByAdmin(user: ICreateUserDTO): Promise<User>
rajdip-b marked this conversation as resolved.
Show resolved Hide resolved
}
8 changes: 8 additions & 0 deletions apps/api/src/user/repository/mock.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { User } from '@prisma/client'
import { IUserRepository } from './interface.repository'
import { users } from '../../common/mock-data/users'
import { ICreateUserDTO } from '../dto/create.user/create.user'

export class MockUserRepository implements IUserRepository {
findUserByEmail(email: string): Promise<User> {
Expand Down Expand Up @@ -52,4 +53,11 @@ export class MockUserRepository implements IUserRepository {
...data
})
}

async createUserByAdmin(user: ICreateUserDTO): Promise<User> {
return Promise.resolve({
id: '1',
...user
})
}
}
9 changes: 9 additions & 0 deletions apps/api/src/user/repository/user.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'
import { PrismaService } from '../../prisma/prisma.service'
import { User } from '@prisma/client'
import { IUserRepository } from './interface.repository'
import { ICreateUserDTO } from '../dto/create.user/create.user'

@Injectable()
export class UserRepository implements IUserRepository {
Expand Down Expand Up @@ -77,4 +78,12 @@ export class UserRepository implements IUserRepository {
}
})
}

async createUserByAdmin(user: ICreateUserDTO): Promise<User> {
return await this.prisma.user.create({
data: {
...user
rajdip-b marked this conversation as resolved.
Show resolved Hide resolved
}
})
}
}
31 changes: 29 additions & 2 deletions apps/api/src/user/service/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { Inject, Injectable, Logger } from '@nestjs/common'
import {
HttpException,
Inject,
Injectable,
Logger
} from '@nestjs/common'
import { UpdateUserDto } from '../dto/update.user/update.user'
import { User } from '@prisma/client'
import {
IUserRepository,
USER_REPOSITORY
} from '../repository/interface.repository'
import { excludeFields } from '../../common/exclude-fields'
import { ICreateUserDTO } from '../dto/create.user/create.user'
import {
IMailService,
MAIL_SERVICE
} from '../../mail/services/interface.service'

@Injectable()
export class UserService {
private readonly log = new Logger(UserService.name)

constructor(
@Inject(USER_REPOSITORY) private readonly repository: IUserRepository
@Inject(USER_REPOSITORY) private readonly repository: IUserRepository,
@Inject(MAIL_SERVICE) private readonly resendService: IMailService
) {}

async getSelf(user: User) {
Expand Down Expand Up @@ -58,4 +69,20 @@ export class UserService {
): Promise<User[]> {
return await this.repository.findUsers(page, limit, sort, order, search)
}

async createUser(user: ICreateUserDTO) {
this.log.log(`Creating user with email ${user.email}`)
const checkDuplicateUser = await this.repository.findUserByEmail(user.email)
if (checkDuplicateUser) {
throw new HttpException('User already exists', 400)
}

const newUser = await this.repository.createUserByAdmin(user)
this.log.log(`Created user with email ${user.email}`)

await this.resendService.accountLoginEmail(newUser.email)
this.log.log(`Sent login email to ${user.email}`)

return newUser
}
}
Loading