fix: Prisma issue fix + Auth done

This commit is contained in:
SauravDhakal
2026-04-12 08:06:05 +05:45
parent aa8deadf1f
commit 2f01adeade
7 changed files with 67 additions and 31 deletions

View File

@@ -5,7 +5,7 @@ import { UserModule } from './user/user.module';
import { AuthModule } from './auth/auth.module';
import { RequestContextMiddleware } from 'core/als/request-context.middleware';
import { RequestContextModule } from 'core/als/request-context.module';
import { ConfigModule } from '@nestjs/config';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { PrismaModule } from './prisma/prisma.module';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { ResponseInterceptor } from 'common/interceptors/response.interceptor';
@@ -72,7 +72,26 @@ import { ExpressAdapter } from '@bull-board/express';
],
})
export class AppModule implements NestModule {
constructor(private readonly configService: ConfigService) { };
configure(consumer: MiddlewareConsumer) {
consumer.apply(RequestContextMiddleware).forRoutes('*paths');
}
// Make sure all required env vars are present
onModuleInit() {
const requiredEnvVars = [
"TOKEN_SECRET",
"DATABASE_URL",
"BULL_MQ_REDIS_HOST",
"BULL_MQ_REDIS_PORT"
]
const missingEnvVars = requiredEnvVars.filter((envVar) => !(this.configService.get<string | number>(envVar)))
if (missingEnvVars.length > 0) {
Logger.error(`One or more env variables are missing. Add: ${missingEnvVars.join(', ')} to env file.`)
process.exit(1)
}
}
}

View File

@@ -76,10 +76,17 @@ export class AuthController {
@IsTempToken()
@UseGuards(AuthGuard)
@Post('/complete-profile')
async completeUserProfile(@Body() body: CompleteProfileSetupRequestDTO): Promise<string> {
await this.authService.completeProfileSetup(body);
async completeUserProfile(@Body() body: CompleteProfileSetupRequestDTO) {
const { accessToken, refreshToken, user } = await this.authService.completeProfileSetup(body);
return 'Welcome';
return {
message: "Welcome to our app",
data: {
accessToken,
refreshToken,
user
}
}
}
logout() { }

View File

@@ -4,10 +4,11 @@ import { AuthController } from './auth.controller';
import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from './guards/auth.guard';
import { UserModule } from 'src/user/user.module';
import { JwtModule } from '@nestjs/jwt';
import { RequestContextModule } from 'core/als/request-context.module';
import { BullModule } from '@nestjs/bullmq';
import { PrismaModule } from 'src/prisma/prisma.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Global()
@Module({
@@ -23,8 +24,16 @@ import { PrismaModule } from 'src/prisma/prisma.module';
BullModule.registerQueue({
name: "mail"
}),
JwtModule.registerAsync({
global: true,
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get<string>("TOKEN_SECRET"),
signOptions: { expiresIn: '7d' }
})
}),
UserModule,
JwtModule,
RequestContextModule,
PrismaModule
],

View File

@@ -83,7 +83,7 @@ export class AuthService {
const now = Number(new Date()) / 1000;
if (!otpExists)
throw new BadRequestException("No user found")
throw new BadRequestException("No OTP request found")
else if (otpExists.otp !== dto.otp)
throw new BadRequestException("Invalid OTP")
else if ((Number(otpExists.expiresAt) / 1000 < now)) {
@@ -217,43 +217,36 @@ export class AuthService {
resetPassword() { }
// TODO: Use nest jwt
// TODO: If remember me is there, sign for like 30d maybe
private async genSignedTokens(token: TokenInputType) {
const accessToken = await this.jwtService.signAsync(token, {
secret: 'demo',
});
const accessToken = await this.jwtService.signAsync(token);
const refreshToken = await this.jwtService.signAsync(
{
userId: token.userId,
},
{
secret: 'demo',
},
);
return { accessToken, refreshToken };
}
private async genSignedTempToken(token: OTPTokenInputType) {
const accessToken = await this.jwtService.signAsync(token, {
secret: 'demo',
});
const accessToken = await this.jwtService.signAsync(token);
const refreshToken = await this.jwtService.signAsync(
{
userId: token.userId,
},
{
secret: 'demo',
},
);
return { accessToken, refreshToken };
}
private genOtp() {
return 123456;
genOtp(): number {
const array = new Uint32Array(1);
crypto.getRandomValues(array);
const otp = array[0] % 900000 + 100000;
return otp;
}
}

View File

@@ -13,6 +13,7 @@ import { Reflector } from '@nestjs/core';
import { PUBLIC_KEY, TEMP_TOKEN_KEY } from 'common/keys';
import { UserService } from 'src/user/user.service';
import { USER_ACCOUNT_STATUS } from 'prisma/generated/prisma/enums';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class AuthGuard implements CanActivate {
@@ -21,6 +22,7 @@ export class AuthGuard implements CanActivate {
private readonly jwtService: JwtService,
private readonly requestContext: RequestContextService,
private readonly userService: UserService,
private readonly configService: ConfigService,
) { }
async canActivate(context: ExecutionContext) {
@@ -42,9 +44,12 @@ export class AuthGuard implements CanActivate {
try {
const payload: JwtPayload = await this.jwtService.verifyAsync(token, {
secret: 'demo',
secret: this.configService.get<string>("TOKEN_SECRET"),
});
if (isTempToken && payload.status !== USER_ACCOUNT_STATUS.pending)
throw new UnauthorizedException()
// TODO: Redis + Org too, blacklist token
const userExists = await this.userService.findById(payload.userId);

View File

@@ -16,6 +16,9 @@ import { TransactionClient } from 'prisma/generated/prisma/internal/prismaNamesp
export class PrismaService
extends PrismaClient
implements OnModuleDestroy, OnModuleInit {
private readonly db: PrismaClient;
constructor(
private readonly ctx: RequestContextService,
private readonly configService: ConfigService,
@@ -31,6 +34,8 @@ export class PrismaService
adapter: adapter,
log: ['info', 'warn'],
});
this.db = new PrismaClient({ adapter, log: ['warn', 'info', 'error'] })
}
async onModuleInit() {
try {
@@ -51,6 +56,6 @@ export class PrismaService
* Else returns itself.
* */
get client(): TransactionClient {
return this.ctx.tx ?? this;
return this.ctx.tx ?? this.db;
}
}

View File

@@ -56,14 +56,14 @@ export class UserService {
}
async findUserForAuth(email: string) {
return await this.prisma.user.findUnique({
return await this.prisma.client.user.findUnique({
where: { email },
omit: { password: false }, // Password is omitted by default, we are just reverting it
});
}
async findById(id: string) {
return await this.prisma.user.findUnique({
return await this.prisma.client.user.findUnique({
where: {
id: id,
},
@@ -71,8 +71,7 @@ export class UserService {
}
async findByEmail(email: string) {
const client = this.prisma.client.user ?? this.prisma.user;
return await client.findUnique({
return await this.prisma.client.user.findUnique({
where: {
email: email,
},
@@ -80,7 +79,7 @@ export class UserService {
}
async updateRefreshToken(id: string, refreshToken: string) {
return await this.prisma.user.update({
return await this.prisma.client.user.update({
where: { id },
data: { refreshToken },
});
@@ -90,8 +89,7 @@ export class UserService {
* USER OTP SERVICES
* */
async findByEmailInOTP(email: string) {
const client = this.prisma.client.userOTP ?? this.prisma.userOTP;
return await client.findUnique({
return await this.prisma.client.userOTP.findUnique({
where: {
email,
},