feat(auth): Implement user signup functionality
This commit introduces a new feature for user signup. It creates `auth.controller.ts`, `auth.dto.ts`, and `auth.schema.ts` for handling user registration requests with validation. Moreover, it enhances `auth.service.ts` to handle the database interaction part and also modifies `auth.module.ts` by adding `AuthController`. Now, the application can handle user registration successfully with proper error handling.
This commit is contained in:
parent
1990bedcfd
commit
de3d1cca05
24
src/auth/auth.controller.ts
Normal file
24
src/auth/auth.controller.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { Body, Controller, HttpCode, HttpStatus, Post } from "@nestjs/common";
|
||||||
|
import { SignUpDto } from "src/auth/auth.dto";
|
||||||
|
import { AuthService } from "src/auth/auth.service";
|
||||||
|
|
||||||
|
@Controller('auth')
|
||||||
|
export class AuthController {
|
||||||
|
constructor(private readonly authService: AuthService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//POST signup
|
||||||
|
@HttpCode(HttpStatus.CREATED)
|
||||||
|
@Post("signup")
|
||||||
|
async signUp(@Body() dto: SignUpDto) {
|
||||||
|
console.log(dto)
|
||||||
|
return this.authService.doRegister(dto)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//POST signin
|
||||||
|
//GET me -- Get current user data via jwt
|
||||||
|
//DELETE me
|
||||||
|
//PATCH me
|
||||||
|
}
|
50
src/auth/auth.dto.ts
Normal file
50
src/auth/auth.dto.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import {
|
||||||
|
IsEmail,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsString,
|
||||||
|
IsStrongPassword,
|
||||||
|
MaxLength,
|
||||||
|
MinLength,
|
||||||
|
} from "class-validator";
|
||||||
|
|
||||||
|
export class SignUpDto {
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(24)
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
firstName: string;
|
||||||
|
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(24)
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
lastName: string;
|
||||||
|
|
||||||
|
@MaxLength(32)
|
||||||
|
@IsEmail()
|
||||||
|
@IsNotEmpty()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsStrongPassword({
|
||||||
|
minLength: 6,
|
||||||
|
minSymbols: 1,
|
||||||
|
})
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignInDto {
|
||||||
|
@MaxLength(32)
|
||||||
|
@IsEmail()
|
||||||
|
@IsNotEmpty()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsStrongPassword({
|
||||||
|
minLength: 6,
|
||||||
|
minSymbols: 1,
|
||||||
|
})
|
||||||
|
password: string;
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { DrizzleModule } from "src/drizzle/drizzle.module";
|
|
||||||
import { AuthService } from "./auth.service";
|
|
||||||
import { CredentialsModule } from "src/credentials/credentials.module";
|
import { CredentialsModule } from "src/credentials/credentials.module";
|
||||||
|
import { DrizzleModule } from "src/drizzle/drizzle.module";
|
||||||
|
import { AuthController } from "./auth.controller";
|
||||||
|
import { AuthService } from "./auth.service";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DrizzleModule, CredentialsModule],
|
imports: [DrizzleModule, CredentialsModule],
|
||||||
providers: [AuthService],
|
providers: [AuthService],
|
||||||
|
controllers: [AuthController],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
31
src/auth/auth.schema.ts
Normal file
31
src/auth/auth.schema.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { UsersTableInsertSchema } from "src/schema";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const SignUpBodySchema = z.object({
|
||||||
|
firstName: z.string({ message: "'firstName' should be a string." }).max(24),
|
||||||
|
lastName: z.string({ message: "'lastName' should be a string." }).max(24),
|
||||||
|
email: z
|
||||||
|
.string({ message: "'email' should be a string." })
|
||||||
|
.max(32, "'email' should be less than 32 characters")
|
||||||
|
.email("Of course 'email' should be an email."),
|
||||||
|
password: z
|
||||||
|
.string({ message: "'password' should be a string." })
|
||||||
|
.min(6)
|
||||||
|
//regex for strong password
|
||||||
|
.regex(
|
||||||
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,32}$/,
|
||||||
|
)
|
||||||
|
.max(32),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SignInBodySchema = z.object({
|
||||||
|
email: z
|
||||||
|
.string({ message: "'email' should be a string." })
|
||||||
|
.max(32, "'email' should be less than 32 characters")
|
||||||
|
.email("Of course 'email' should be an email."),
|
||||||
|
|
||||||
|
password: z
|
||||||
|
.string({ message: "'password' should be a string." })
|
||||||
|
.min(6)
|
||||||
|
.max(32),
|
||||||
|
});
|
@ -1,27 +1,80 @@
|
|||||||
// biome-ignore lint/style/useImportType: used by Next.js
|
import * as console from "node:console";
|
||||||
import { Injectable, OnModuleInit } from "@nestjs/common";
|
import {
|
||||||
// biome-ignore lint/style/useImportType: used by Next.js
|
Injectable,
|
||||||
|
OnModuleInit,
|
||||||
|
UnauthorizedException,
|
||||||
|
} from "@nestjs/common";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { SignUpBodySchema } from "src/auth/auth.schema";
|
||||||
|
import { CredentialsService } from "src/credentials/credentials.service";
|
||||||
import { DrizzleService } from "src/drizzle/drizzle.service";
|
import { DrizzleService } from "src/drizzle/drizzle.service";
|
||||||
import { UsersTable } from "src/schema";
|
import { UsersTable } from "src/schema";
|
||||||
// biome-ignore lint/style/useImportType: used by Next.js
|
import { SignInDto, SignUpDto } from "src/auth/auth.dto";
|
||||||
import { CredentialsService } from "src/credentials/credentials.service";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService implements OnModuleInit {
|
export class AuthService implements OnModuleInit {
|
||||||
constructor(
|
constructor(
|
||||||
private db: DrizzleService,
|
private db: DrizzleService,
|
||||||
private credentials: CredentialsService
|
private credentials: CredentialsService,
|
||||||
) {}
|
) {}
|
||||||
doRegister() {}
|
async doRegister(data: SignUpDto) {
|
||||||
doLogin() {}
|
console.log(data);
|
||||||
|
const existingUser = await this.db
|
||||||
|
.use()
|
||||||
|
.select()
|
||||||
|
.from(UsersTable)
|
||||||
|
.where(eq(UsersTable.email, data.email))
|
||||||
|
.prepare("userByEmail")
|
||||||
|
.execute();
|
||||||
|
if (existingUser.length !== 0)
|
||||||
|
throw new UnauthorizedException("Already exist");
|
||||||
|
const query = await this.db
|
||||||
|
.use()
|
||||||
|
.insert(UsersTable)
|
||||||
|
.values({
|
||||||
|
firstName: data.firstName,
|
||||||
|
lastName: data.lastName,
|
||||||
|
email: data.email,
|
||||||
|
hash: await this.credentials.hash(data.password),
|
||||||
|
})
|
||||||
|
.returning()
|
||||||
|
.prepare("insertUser")
|
||||||
|
.execute()
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
throw new UnauthorizedException(
|
||||||
|
"Error occurred while inserting user",
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
message: "User created, check your email for validation.",
|
||||||
|
token: await this.credentials.signAuthToken({sub: query[0].uuid})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doLogin(data: SignInDto) {}
|
||||||
|
|
||||||
async fetchUser(userId: string) {
|
async fetchUser(userId: string) {
|
||||||
const userInDb = await this.db.use().select().from(UsersTable);
|
//TODO Pagination
|
||||||
console.log("Users : \n", userInDb);
|
const usersInDb = await this.db.use().select().from(UsersTable);
|
||||||
|
const result = {
|
||||||
|
total: usersInDb.length,
|
||||||
|
users: usersInDb.map((user)=>{
|
||||||
|
delete user.hash
|
||||||
|
return {
|
||||||
|
...user
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log(result)
|
||||||
}
|
}
|
||||||
updateUser() {}
|
updateUser() {}
|
||||||
deleteUser() {}
|
deleteUser() {}
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
await this.fetchUser("ee");
|
setTimeout(()=>{
|
||||||
|
this.fetchUser("ee");
|
||||||
|
}, 2000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user