clean up and logOut
This commit is contained in:
parent
b38261e387
commit
71b73d5fcb
@ -8,38 +8,38 @@ import {
|
||||
Request,
|
||||
Logger,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { LoginDto } from '../dto/login.dto';
|
||||
import { CreateUserDto } from '../dto/create-user.dto';
|
||||
import { JwtAuthGuard } from './jwt-auth.guard';
|
||||
import { AdminGuard } from './admin.guard';
|
||||
} from "@nestjs/common";
|
||||
import { AuthService } from "./auth.service";
|
||||
import { LoginDto } from "../dto/login.dto";
|
||||
import { CreateUserDto } from "../dto/create-user.dto";
|
||||
import { JwtAuthGuard } from "./jwt-auth.guard";
|
||||
import { AdminGuard } from "./admin.guard";
|
||||
//@UseGuards(JwtAuthGuard, AdminGuard)
|
||||
@Controller('auth')
|
||||
@Controller("auth")
|
||||
export class AuthController {
|
||||
private readonly logger = new Logger(AuthController.name);
|
||||
|
||||
constructor(private authService: AuthService) {
|
||||
this.logger.log('AuthController initialized');
|
||||
this.logger.log("AuthController initialized");
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
@Post("login")
|
||||
async login(@Body() loginDto: LoginDto) {
|
||||
this.logger.log('=== Login endpoint hit ===');
|
||||
this.logger.debug('Raw request body:', {
|
||||
this.logger.log("=== Login endpoint hit ===");
|
||||
this.logger.debug("Raw request body:", {
|
||||
username: loginDto.username,
|
||||
email: loginDto.email,
|
||||
hasPassword: !!loginDto.password,
|
||||
});
|
||||
|
||||
const email = loginDto.getEmail();
|
||||
this.logger.debug('Normalized login request:', {
|
||||
this.logger.debug("Normalized login request:", {
|
||||
email,
|
||||
hasPassword: !!loginDto.password,
|
||||
});
|
||||
|
||||
try {
|
||||
this.logger.debug('Calling AuthService.validateUser...');
|
||||
this.logger.debug("Calling AuthService.validateUser...");
|
||||
const user = await this.authService.validateUser(
|
||||
email,
|
||||
loginDto.password,
|
||||
@ -47,20 +47,20 @@ export class AuthController {
|
||||
|
||||
if (!user) {
|
||||
this.logger.warn(`Login failed: Invalid credentials for ${email}`);
|
||||
throw new UnauthorizedException('Invalid email or password');
|
||||
throw new UnauthorizedException("Invalid email or password");
|
||||
}
|
||||
|
||||
this.logger.debug('User validated successfully:', {
|
||||
this.logger.debug("User validated successfully:", {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
isAdmin: user.isAdmin,
|
||||
});
|
||||
|
||||
this.logger.debug('Calling AuthService.login...');
|
||||
this.logger.debug("Calling AuthService.login...");
|
||||
const result = await this.authService.login(user);
|
||||
|
||||
this.logger.debug('Login successful, returning response:', {
|
||||
this.logger.debug("Login successful, returning response:", {
|
||||
hasAccessToken: !!result.access_token,
|
||||
user: {
|
||||
id: result.user.id,
|
||||
@ -76,7 +76,7 @@ export class AuthController {
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.logger.error('Login failed:', {
|
||||
this.logger.error("Login failed:", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
body: {
|
||||
@ -85,35 +85,35 @@ export class AuthController {
|
||||
hasPassword: !!loginDto.password,
|
||||
},
|
||||
});
|
||||
throw new UnauthorizedException('Invalid email or password');
|
||||
throw new UnauthorizedException("Invalid email or password");
|
||||
}
|
||||
}
|
||||
|
||||
@Post('register')
|
||||
@Post("register")
|
||||
async register(@Body() createUserDto: CreateUserDto) {
|
||||
console.log('=== Registration endpoint hit ===');
|
||||
this.logger.log('=== Registration endpoint hit ===');
|
||||
console.log('Registration request received:', createUserDto);
|
||||
this.logger.log('Registration request received:', {
|
||||
console.log("=== Registration endpoint hit ===");
|
||||
this.logger.log("=== Registration endpoint hit ===");
|
||||
console.log("Registration request received:", createUserDto);
|
||||
this.logger.log("Registration request received:", {
|
||||
email: createUserDto.email,
|
||||
name: createUserDto.name,
|
||||
hasPassword: !!createUserDto.password
|
||||
hasPassword: !!createUserDto.password,
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('Calling AuthService.createUser...');
|
||||
this.logger.log('Calling AuthService.createUser...');
|
||||
console.log("Calling AuthService.createUser...");
|
||||
this.logger.log("Calling AuthService.createUser...");
|
||||
const result = await this.authService.createUser(createUserDto);
|
||||
console.log('Registration successful:', result);
|
||||
this.logger.log('Registration successful:', {
|
||||
console.log("Registration successful:", result);
|
||||
this.logger.log("Registration successful:", {
|
||||
id: result.id,
|
||||
email: result.email,
|
||||
name: result.name,
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Registration failed:', error);
|
||||
this.logger.error('Registration failed:', {
|
||||
console.error("Registration failed:", error);
|
||||
this.logger.error("Registration failed:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -124,25 +124,25 @@ export class AuthController {
|
||||
}
|
||||
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
@Post('create-admin')
|
||||
@Post("create-admin")
|
||||
async createAdmin(@Body() createUserDto: CreateUserDto) {
|
||||
this.logger.log('=== Create admin endpoint hit ===');
|
||||
this.logger.debug('Admin creation request received:', {
|
||||
this.logger.log("=== Create admin endpoint hit ===");
|
||||
this.logger.debug("Admin creation request received:", {
|
||||
email: createUserDto.email,
|
||||
name: createUserDto.name,
|
||||
});
|
||||
|
||||
try {
|
||||
this.logger.debug('Calling AuthService.createUser with isAdmin=true...');
|
||||
this.logger.debug("Calling AuthService.createUser with isAdmin=true...");
|
||||
const result = await this.authService.createUser(createUserDto, true);
|
||||
this.logger.debug('Admin creation successful:', {
|
||||
this.logger.debug("Admin creation successful:", {
|
||||
id: result.id,
|
||||
email: result.email,
|
||||
name: result.name,
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.logger.error('Admin creation failed:', {
|
||||
this.logger.error("Admin creation failed:", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
@ -151,29 +151,37 @@ export class AuthController {
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user-info')
|
||||
@Get("user-info")
|
||||
async getUserInfo(@Request() req) {
|
||||
return this.authService.getUserInfo(req.user.userId);
|
||||
}
|
||||
|
||||
@Post('forgot-password')
|
||||
@Post("forgot-password")
|
||||
async forgotPassword(@Body() { email }: { email: string }) {
|
||||
if (!email) {
|
||||
throw new BadRequestException('Email is required');
|
||||
throw new BadRequestException("Email is required");
|
||||
}
|
||||
return this.authService.sendPasswordResetToken(email);
|
||||
}
|
||||
|
||||
@Post('reset-password')
|
||||
@Post("reset-password")
|
||||
async resetPassword(
|
||||
@Body() { token, newPassword }: { token: string; newPassword: string }
|
||||
@Body() { token, newPassword }: { token: string; newPassword: string },
|
||||
) {
|
||||
if (!token || !newPassword) {
|
||||
throw new BadRequestException('Token and new password are required');
|
||||
throw new BadRequestException("Token and new password are required");
|
||||
}
|
||||
if (newPassword.length < 6) {
|
||||
throw new BadRequestException('Password must be at least 6 characters long');
|
||||
throw new BadRequestException(
|
||||
"Password must be at least 6 characters long",
|
||||
);
|
||||
}
|
||||
return this.authService.resetPasswordWithToken(token, newPassword);
|
||||
}
|
||||
|
||||
@Post("logout")
|
||||
async logout(@Request() req) {
|
||||
await this.authService.logout(req.user.userId);
|
||||
return { message: "Logged out successfully" };
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,17 +221,6 @@ export class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
// async getUserInfo(userId: number) {
|
||||
// return this.prisma.user.findUnique({
|
||||
// where: { id: userId },
|
||||
// select: {
|
||||
// id: true,
|
||||
// name: true,
|
||||
// email: true,
|
||||
// isAdmin: true,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
async getUserInfo(userId: number) {
|
||||
if (!userId) {
|
||||
throw new Error("User ID is required");
|
||||
@ -327,9 +316,9 @@ export class AuthService {
|
||||
where: {
|
||||
token,
|
||||
expiresAt: {
|
||||
gt: new Date(), // Token must not be expired
|
||||
gt: new Date(),
|
||||
},
|
||||
used: false, // Token must not be used
|
||||
used: false,
|
||||
},
|
||||
include: {
|
||||
user: true,
|
||||
@ -386,4 +375,9 @@ export class AuthService {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async logout(userId: string): Promise<void> {
|
||||
return console.log("User logged out:", userId);
|
||||
this.logger.log("User logged out:", userId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export const getDatabaseUrl = () => {
|
||||
const url = process.env.DATABASE_URL;
|
||||
console.log("Database URL:", url); // For debugging
|
||||
console.log("Database URL:", url);
|
||||
return url;
|
||||
};
|
||||
|
||||
@ -1,9 +1,21 @@
|
||||
import { Controller, Get, Param, Req, Res, UseGuards, Logger, Request, Post, UseInterceptors, UploadedFile, Body } from '@nestjs/common';
|
||||
import { Response } from 'express';
|
||||
import { DocumentsService } from './documents.service';
|
||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||
import { S3Service } from '../s3/s3.service';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Logger,
|
||||
Param,
|
||||
Post,
|
||||
Request,
|
||||
Res,
|
||||
UploadedFile,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from "@nestjs/common";
|
||||
import { FileInterceptor } from "@nestjs/platform-express";
|
||||
import { Response } from "express";
|
||||
import { JwtAuthGuard } from "../auth/jwt-auth.guard";
|
||||
import { S3Service } from "../s3/s3.service";
|
||||
import { DocumentsService } from "./documents.service";
|
||||
|
||||
interface S3File {
|
||||
buffer: Buffer;
|
||||
@ -12,28 +24,28 @@ interface S3File {
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
@Controller('documents')
|
||||
@Controller("documents")
|
||||
export class DocumentsController {
|
||||
private readonly logger = new Logger(DocumentsController.name);
|
||||
|
||||
constructor(
|
||||
private readonly documentsService: DocumentsService,
|
||||
private readonly s3Service: S3Service
|
||||
private readonly s3Service: S3Service,
|
||||
) {
|
||||
this.logger.log('DocumentsController initialized');
|
||||
this.logger.log("DocumentsController initialized");
|
||||
}
|
||||
|
||||
@Post('upload')
|
||||
@Post("upload")
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseInterceptors(FileInterceptor('file'))
|
||||
@UseInterceptors(FileInterceptor("file"))
|
||||
async uploadDocument(
|
||||
@UploadedFile() file: Express.Multer.File,
|
||||
@Body('title') title: string,
|
||||
@Body('sharedWithId') sharedWithId: string,
|
||||
@Body("title") title: string,
|
||||
@Body("sharedWithId") sharedWithId: string,
|
||||
@Request() req,
|
||||
) {
|
||||
this.logger.log('=== Document upload endpoint hit ===');
|
||||
this.logger.debug('Upload request received:', {
|
||||
this.logger.log("=== Document upload endpoint hit ===");
|
||||
this.logger.debug("Upload request received:", {
|
||||
fileName: file?.originalname,
|
||||
fileSize: file?.size,
|
||||
title,
|
||||
@ -49,7 +61,7 @@ export class DocumentsController {
|
||||
req.user.id,
|
||||
);
|
||||
|
||||
this.logger.debug('Document upload successful:', {
|
||||
this.logger.debug("Document upload successful:", {
|
||||
documentId: result.id,
|
||||
title: result.title,
|
||||
s3Key: result.s3Key,
|
||||
@ -57,7 +69,7 @@ export class DocumentsController {
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.logger.error('Document upload failed:', {
|
||||
this.logger.error("Document upload failed:", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
@ -65,18 +77,18 @@ export class DocumentsController {
|
||||
}
|
||||
}
|
||||
|
||||
@Get('shared/:userId')
|
||||
@Get("shared/:userId")
|
||||
@UseGuards(JwtAuthGuard)
|
||||
async getSharedDocuments(@Param('userId') userId: string) {
|
||||
async getSharedDocuments(@Param("userId") userId: string) {
|
||||
return this.documentsService.getClientDocuments(Number(userId));
|
||||
}
|
||||
|
||||
@Get('download/:key')
|
||||
@Get("download/:key")
|
||||
@UseGuards(JwtAuthGuard)
|
||||
async downloadDocument(
|
||||
@Param('key') key: string,
|
||||
@Param("key") key: string,
|
||||
@Request() req,
|
||||
@Res() res: Response
|
||||
@Res() res: Response,
|
||||
) {
|
||||
try {
|
||||
this.logger.debug(`Download request for key: ${key}`);
|
||||
@ -85,41 +97,42 @@ export class DocumentsController {
|
||||
this.logger.debug(`Decoded key: ${decodedKey}`);
|
||||
|
||||
// Get document from database first to verify access
|
||||
const document = await this.documentsService.findDocumentByS3Key(decodedKey);
|
||||
const document =
|
||||
await this.documentsService.findDocumentByS3Key(decodedKey);
|
||||
|
||||
if (!document) {
|
||||
return res.status(404).json({ message: 'Document not found' });
|
||||
return res.status(404).json({ message: "Document not found" });
|
||||
}
|
||||
|
||||
// Verify user has access to this document
|
||||
const hasAccess = await this.documentsService.verifyDocumentAccess(
|
||||
document.id,
|
||||
req.user.id
|
||||
req.user.id,
|
||||
);
|
||||
|
||||
if (!hasAccess) {
|
||||
return res.status(403).json({ message: 'Access denied' });
|
||||
return res.status(403).json({ message: "Access denied" });
|
||||
}
|
||||
|
||||
// Get the file from S3
|
||||
const file = await this.s3Service.getFile(decodedKey);
|
||||
|
||||
if (!file || !file.buffer) {
|
||||
return res.status(404).json({ message: 'File not found in storage' });
|
||||
return res.status(404).json({ message: "File not found in storage" });
|
||||
}
|
||||
|
||||
res.set({
|
||||
'Content-Type': file.contentType || 'application/octet-stream',
|
||||
'Content-Length': file.contentLength,
|
||||
'Content-Disposition': `attachment; filename="${encodeURIComponent(file.fileName)}"`,
|
||||
"Content-Type": file.contentType || "application/octet-stream",
|
||||
"Content-Length": file.contentLength,
|
||||
"Content-Disposition": `attachment; filename="${encodeURIComponent(file.fileName)}"`,
|
||||
});
|
||||
|
||||
return res.send(file.buffer);
|
||||
} catch (error) {
|
||||
this.logger.error('Download error:', error);
|
||||
this.logger.error("Download error:", error);
|
||||
return res.status(500).json({
|
||||
message: 'Failed to download file',
|
||||
error: error.message
|
||||
message: "Failed to download file",
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ export class EmailService {
|
||||
private readonly from: string;
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
console.log("Initializing EmailService..."); // Direct console log for debugging
|
||||
console.log("Initializing EmailService...");
|
||||
this.logger.log("Initializing EmailService...");
|
||||
|
||||
// Load config
|
||||
@ -88,7 +88,7 @@ export class EmailService {
|
||||
|
||||
const info = await this.transporter.sendMail(mailOptions);
|
||||
|
||||
console.log("Email sent successfully:", info); // Direct console log
|
||||
console.log("Email sent successfully:", info);
|
||||
this.logger.log("Email sent successfully:", {
|
||||
messageId: info.messageId,
|
||||
response: info.response,
|
||||
@ -97,7 +97,7 @@ export class EmailService {
|
||||
envelope: info.envelope,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to send email:", error); // Direct console log
|
||||
console.error("Failed to send email:", error);
|
||||
this.logger.error("Failed to send email:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
|
||||
@ -1,7 +1,15 @@
|
||||
import { Injectable, Logger, InternalServerErrorException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { S3File } from '../interfaces/s3-file.interface';
|
||||
import {
|
||||
Injectable,
|
||||
Logger,
|
||||
InternalServerErrorException,
|
||||
} from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import {
|
||||
S3Client,
|
||||
PutObjectCommand,
|
||||
GetObjectCommand,
|
||||
} from "@aws-sdk/client-s3";
|
||||
import { S3File } from "../interfaces/s3-file.interface";
|
||||
|
||||
@Injectable()
|
||||
export class S3Service {
|
||||
@ -10,12 +18,14 @@ export class S3Service {
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.s3Client = new S3Client({
|
||||
region: this.configService.get<string>('AWS_REGION'),
|
||||
region: this.configService.get<string>("AWS_REGION"),
|
||||
credentials: {
|
||||
accessKeyId: this.configService.get<string>('AWS_ACCESS_KEY_ID'),
|
||||
secretAccessKey: this.configService.get<string>('AWS_SECRET_ACCESS_KEY'),
|
||||
accessKeyId: this.configService.get<string>("AWS_ACCESS_KEY_ID"),
|
||||
secretAccessKey: this.configService.get<string>(
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
),
|
||||
},
|
||||
endpoint: this.configService.get<string>('AWS_ENDPOINT_URL'),
|
||||
endpoint: this.configService.get<string>("AWS_ENDPOINT_URL"),
|
||||
forcePathStyle: true, // Required for Contabo Object Storage
|
||||
});
|
||||
}
|
||||
@ -25,7 +35,7 @@ export class S3Service {
|
||||
const key = `${folder}/${Date.now()}-${file.originalname}`;
|
||||
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: this.configService.get<string>('AWS_S3_BUCKET_NAME'),
|
||||
Bucket: this.configService.get<string>("AWS_S3_BUCKET_NAME"),
|
||||
Key: key,
|
||||
Body: file.buffer,
|
||||
ContentType: file.mimetype,
|
||||
@ -37,14 +47,16 @@ export class S3Service {
|
||||
return key;
|
||||
} catch (error) {
|
||||
this.logger.error(`Error uploading file to S3: ${error.message}`);
|
||||
throw new InternalServerErrorException('Failed to upload file to storage');
|
||||
throw new InternalServerErrorException(
|
||||
"Failed to upload file to storage",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getFile(key: string): Promise<S3File> {
|
||||
try {
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: this.configService.get<string>('AWS_S3_BUCKET_NAME'),
|
||||
Bucket: this.configService.get<string>("AWS_S3_BUCKET_NAME"),
|
||||
Key: key,
|
||||
});
|
||||
|
||||
@ -58,15 +70,16 @@ export class S3Service {
|
||||
|
||||
return {
|
||||
buffer,
|
||||
contentType: response.ContentType || 'application/octet-stream',
|
||||
contentType: response.ContentType || "application/octet-stream",
|
||||
contentLength: response.ContentLength || buffer.length,
|
||||
fileName: key.split('/').pop() || 'download',
|
||||
fileName: key.split("-").pop() || "download",
|
||||
// fileName: key.split("-").pop() || "download",
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(`Error getting file from S3: ${error.message}`);
|
||||
throw new InternalServerErrorException('Failed to retrieve file from storage');
|
||||
throw new InternalServerErrorException(
|
||||
"Failed to retrieve file from storage",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,7 +48,9 @@ export const downloadDocument = async (key) => {
|
||||
link.href = url;
|
||||
|
||||
// Extract filename from key
|
||||
const fileName = key.split("/").pop();
|
||||
const fileName = key.split("-").pop();
|
||||
// const fileName = key.split("/").pop();
|
||||
|
||||
link.download = fileName;
|
||||
|
||||
document.body.appendChild(link);
|
||||
@ -106,7 +108,6 @@ export const getAllUsers = () => api.get("/admin/users");
|
||||
export const resetUserPassword = (userId, newPassword) =>
|
||||
api.post(`/admin/users/${userId}/reset-password`, { password: newPassword });
|
||||
|
||||
// Password reset endpoints
|
||||
export const forgotPassword = (email) =>
|
||||
api.post("/auth/forgot-password", { email });
|
||||
export const resetPassword = (token, newPassword) =>
|
||||
@ -121,4 +122,5 @@ api.interceptors.response.use(
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
export const logout = () => api.post("/auth/logout");
|
||||
export default api;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user