346 lines
9.9 KiB
TypeScript
346 lines
9.9 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
import { S3Service } from '../s3/s3.service';
|
|
import { UpdateDocumentDto } from '../dto/update-document.dto';
|
|
import { CreateUserDto } from '../dto/create-user.dto';
|
|
import * as bcrypt from 'bcrypt';
|
|
import { EmailService } from '../email/email.service';
|
|
|
|
@Injectable()
|
|
export class AdminService {
|
|
private readonly logger = new Logger(AdminService.name);
|
|
|
|
constructor(
|
|
private readonly prisma: PrismaService,
|
|
private readonly s3Service: S3Service,
|
|
private readonly emailService: EmailService,
|
|
) {}
|
|
|
|
async getAllDocuments() {
|
|
return this.prisma.document.findMany({
|
|
include: {
|
|
uploadedBy: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
sharedWith: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: {
|
|
createdAt: 'desc',
|
|
},
|
|
});
|
|
}
|
|
|
|
async getAllUsers() {
|
|
return this.prisma.user.findMany();
|
|
}
|
|
|
|
async createUser(createUserDto: CreateUserDto) {
|
|
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
|
|
|
|
return this.prisma.user.create({
|
|
data: {
|
|
...createUserDto,
|
|
password: hashedPassword,
|
|
},
|
|
});
|
|
}
|
|
|
|
async updateDocument(
|
|
id: number,
|
|
updateDocumentDto: UpdateDocumentDto,
|
|
file?: Express.Multer.File,
|
|
) {
|
|
let s3Key = undefined;
|
|
if (file) {
|
|
s3Key = await this.s3Service.uploadFile(file, 'documents');
|
|
}
|
|
|
|
return this.prisma.document.update({
|
|
where: { id },
|
|
data: {
|
|
...updateDocumentDto,
|
|
...(s3Key && { s3Key }),
|
|
},
|
|
});
|
|
}
|
|
|
|
async shareDocument(documentId: number, userId: number) {
|
|
this.logger.log('=== Starting document share process ===');
|
|
console.log('=== Starting document share process ===');
|
|
this.logger.debug('Share request:', { documentId, userId });
|
|
console.log('Share request:', { documentId, userId });
|
|
|
|
try {
|
|
// Get the document with its current data
|
|
const document = await this.prisma.document.findUnique({
|
|
where: { id: documentId },
|
|
include: {
|
|
uploadedBy: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!document) {
|
|
this.logger.error('Document not found:', { documentId });
|
|
console.error('Document not found:', { documentId });
|
|
throw new Error('Document not found');
|
|
}
|
|
|
|
// Get the user we're sharing with
|
|
const shareUser = await this.prisma.user.findUnique({
|
|
where: { id: userId },
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
});
|
|
|
|
if (!shareUser) {
|
|
this.logger.error('User not found:', { userId });
|
|
console.error('User not found:', { userId });
|
|
throw new Error('User not found');
|
|
}
|
|
|
|
// Update the document sharing
|
|
const updatedDocument = await this.prisma.document.update({
|
|
where: { id: documentId },
|
|
data: {
|
|
sharedWith: {
|
|
connect: { id: userId },
|
|
},
|
|
},
|
|
include: {
|
|
uploadedBy: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
sharedWith: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// Send email notification to the user we're sharing with
|
|
this.logger.log('Sending email notification to shared user:', {
|
|
userId: shareUser.id,
|
|
email: shareUser.email,
|
|
name: shareUser.name,
|
|
documentTitle: document.title
|
|
});
|
|
console.log('Sending email notification to shared user:', {
|
|
userId: shareUser.id,
|
|
email: shareUser.email,
|
|
name: shareUser.name,
|
|
documentTitle: document.title
|
|
});
|
|
|
|
try {
|
|
console.log('Attempting to send email notification...');
|
|
await this.emailService.sendDocumentNotification(
|
|
shareUser.email,
|
|
shareUser.name,
|
|
document.title,
|
|
'shared'
|
|
);
|
|
console.log('Email notification sent successfully');
|
|
this.logger.log('Email notification sent successfully');
|
|
} catch (emailError) {
|
|
// Log the full error details
|
|
console.error('Failed to send email notification:', emailError);
|
|
this.logger.error('Failed to send email notification:', {
|
|
error: emailError.message,
|
|
code: emailError.code,
|
|
command: emailError.command,
|
|
response: emailError.response,
|
|
responseCode: emailError.responseCode,
|
|
stack: emailError.stack,
|
|
});
|
|
// Don't throw the error, just log it and continue
|
|
}
|
|
|
|
this.logger.log('=== Document share process completed ===');
|
|
console.log('=== Document share process completed ===');
|
|
return updatedDocument;
|
|
} catch (error) {
|
|
this.logger.error('Error in shareDocument:', {
|
|
error: error.message,
|
|
code: error.code,
|
|
stack: error.stack,
|
|
});
|
|
console.error('Error in shareDocument:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async updateDocumentStatus(documentId: number, status: string) {
|
|
return this.prisma.document.update({
|
|
where: { id: documentId },
|
|
data: { status },
|
|
});
|
|
}
|
|
|
|
async uploadDocument(
|
|
file: Express.Multer.File,
|
|
title: string,
|
|
sharedWithId: number,
|
|
uploadedById: number
|
|
) {
|
|
this.logger.log('=== Starting document upload process ===');
|
|
this.logger.debug('Upload parameters:', {
|
|
title,
|
|
sharedWithId,
|
|
uploadedById,
|
|
fileName: file.originalname,
|
|
fileSize: file.size,
|
|
});
|
|
|
|
try {
|
|
this.logger.debug('Uploading file to S3...');
|
|
const s3Key = await this.s3Service.uploadFile(file, 'documents');
|
|
this.logger.debug(`File uploaded to S3 successfully with key: ${s3Key}`);
|
|
|
|
this.logger.debug('Creating document record in database...');
|
|
const document = await this.prisma.document.create({
|
|
data: {
|
|
title,
|
|
s3Key,
|
|
status: 'pending',
|
|
sharedWith: {
|
|
connect: { id: sharedWithId }
|
|
},
|
|
uploadedBy: {
|
|
connect: { id: uploadedById }
|
|
}
|
|
},
|
|
include: {
|
|
uploadedBy: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
sharedWith: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
email: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
this.logger.debug('Document record created:', {
|
|
id: document.id,
|
|
title: document.title,
|
|
uploadedBy: document.uploadedBy,
|
|
sharedWith: document.sharedWith,
|
|
});
|
|
|
|
// Send email notifications
|
|
this.logger.log('=== Starting email notification process ===');
|
|
|
|
// Notify the user who the document is shared with
|
|
const sharedUser = document.sharedWith[0];
|
|
if (sharedUser) {
|
|
this.logger.debug(`Preparing to send notification to shared user:`, {
|
|
id: sharedUser.id,
|
|
email: sharedUser.email,
|
|
name: sharedUser.name,
|
|
});
|
|
try {
|
|
this.logger.debug('Calling EmailService.sendDocumentNotification for shared user...');
|
|
await this.emailService.sendDocumentNotification(
|
|
sharedUser.email,
|
|
sharedUser.name,
|
|
document.title,
|
|
'shared'
|
|
);
|
|
this.logger.debug('Shared user notification sent successfully');
|
|
} catch (error) {
|
|
this.logger.error('Failed to send notification to shared user:', {
|
|
error: error.message,
|
|
code: error.code,
|
|
command: error.command,
|
|
stack: error.stack,
|
|
});
|
|
// Log the email service instance to verify it's properly injected
|
|
this.logger.debug('EmailService instance:', {
|
|
exists: !!this.emailService,
|
|
type: typeof this.emailService,
|
|
methods: Object.keys(Object.getPrototypeOf(this.emailService)),
|
|
});
|
|
}
|
|
} else {
|
|
this.logger.warn('No shared user found in the document record');
|
|
}
|
|
|
|
// Notify the uploader
|
|
const uploader = document.uploadedBy;
|
|
if (uploader) {
|
|
this.logger.debug(`Preparing to send notification to uploader:`, {
|
|
id: uploader.id,
|
|
email: uploader.email,
|
|
name: uploader.name,
|
|
});
|
|
try {
|
|
this.logger.debug('Calling EmailService.sendDocumentNotification for uploader...');
|
|
await this.emailService.sendDocumentNotification(
|
|
uploader.email,
|
|
uploader.name,
|
|
document.title,
|
|
'uploaded'
|
|
);
|
|
this.logger.debug('Uploader notification sent successfully');
|
|
} catch (error) {
|
|
this.logger.error('Failed to send notification to uploader:', {
|
|
error: error.message,
|
|
code: error.code,
|
|
command: error.command,
|
|
stack: error.stack,
|
|
});
|
|
// Log the email service instance to verify it's properly injected
|
|
this.logger.debug('EmailService instance:', {
|
|
exists: !!this.emailService,
|
|
type: typeof this.emailService,
|
|
methods: Object.keys(Object.getPrototypeOf(this.emailService)),
|
|
});
|
|
}
|
|
} else {
|
|
this.logger.warn('No uploader found in the document record');
|
|
}
|
|
|
|
this.logger.log('=== Document upload process completed ===');
|
|
return document;
|
|
} catch (error) {
|
|
this.logger.error('Error in uploadDocument:', {
|
|
error: error.message,
|
|
code: error.code,
|
|
stack: error.stack,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
} |