Notification updates
This commit is contained in:
@@ -17,11 +17,11 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Documents list requested', {
|
||||
operation: 'documents.list',
|
||||
user_id: userId,
|
||||
userId,
|
||||
filters: {
|
||||
vehicle_id: request.query.vehicleId,
|
||||
vehicleId: request.query.vehicleId,
|
||||
type: request.query.type,
|
||||
expires_before: request.query.expiresBefore,
|
||||
expiresBefore: request.query.expiresBefore,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -33,8 +33,8 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Documents list retrieved', {
|
||||
operation: 'documents.list.success',
|
||||
user_id: userId,
|
||||
document_count: docs.length,
|
||||
userId,
|
||||
documentCount: docs.length,
|
||||
});
|
||||
|
||||
return reply.code(200).send(docs);
|
||||
@@ -46,26 +46,26 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document get requested', {
|
||||
operation: 'documents.get',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
|
||||
const doc = await this.service.getDocument(userId, documentId);
|
||||
if (!doc) {
|
||||
logger.warn('Document not found', {
|
||||
operation: 'documents.get.not_found',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
return reply.code(404).send({ error: 'Not Found' });
|
||||
}
|
||||
|
||||
logger.info('Document retrieved', {
|
||||
operation: 'documents.get.success',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
vehicle_id: doc.vehicle_id,
|
||||
document_type: doc.document_type,
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId: doc.vehicleId,
|
||||
documentType: doc.documentType,
|
||||
});
|
||||
|
||||
return reply.code(200).send(doc);
|
||||
@@ -76,9 +76,9 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document create requested', {
|
||||
operation: 'documents.create',
|
||||
user_id: userId,
|
||||
vehicle_id: request.body.vehicle_id,
|
||||
document_type: request.body.document_type,
|
||||
userId,
|
||||
vehicleId: request.body.vehicleId,
|
||||
documentType: request.body.documentType,
|
||||
title: request.body.title,
|
||||
});
|
||||
|
||||
@@ -86,10 +86,10 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document created', {
|
||||
operation: 'documents.create.success',
|
||||
user_id: userId,
|
||||
document_id: created.id,
|
||||
vehicle_id: created.vehicle_id,
|
||||
document_type: created.document_type,
|
||||
userId,
|
||||
documentId: created.id,
|
||||
vehicleId: created.vehicleId,
|
||||
documentType: created.documentType,
|
||||
title: created.title,
|
||||
});
|
||||
|
||||
@@ -102,26 +102,26 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document update requested', {
|
||||
operation: 'documents.update',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
update_fields: Object.keys(request.body),
|
||||
userId,
|
||||
documentId,
|
||||
updateFields: Object.keys(request.body),
|
||||
});
|
||||
|
||||
const updated = await this.service.updateDocument(userId, documentId, request.body);
|
||||
if (!updated) {
|
||||
logger.warn('Document not found for update', {
|
||||
operation: 'documents.update.not_found',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
return reply.code(404).send({ error: 'Not Found' });
|
||||
}
|
||||
|
||||
logger.info('Document updated', {
|
||||
operation: 'documents.update.success',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
vehicle_id: updated.vehicle_id,
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId: updated.vehicleId,
|
||||
title: updated.title,
|
||||
});
|
||||
|
||||
@@ -134,28 +134,28 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document delete requested', {
|
||||
operation: 'documents.delete',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
|
||||
// If object exists, delete it from storage first
|
||||
const existing = await this.service.getDocument(userId, documentId);
|
||||
if (existing && existing.storage_bucket && existing.storage_key) {
|
||||
if (existing && existing.storageBucket && existing.storageKey) {
|
||||
const storage = getStorageService();
|
||||
try {
|
||||
await storage.deleteObject(existing.storage_bucket, existing.storage_key);
|
||||
await storage.deleteObject(existing.storageBucket, existing.storageKey);
|
||||
logger.info('Document file deleted from storage', {
|
||||
operation: 'documents.delete.storage_cleanup',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
storage_key: existing.storage_key,
|
||||
userId,
|
||||
documentId,
|
||||
storageKey: existing.storageKey,
|
||||
});
|
||||
} catch (e) {
|
||||
logger.warn('Failed to delete document file from storage', {
|
||||
operation: 'documents.delete.storage_cleanup_failed',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
storage_key: existing.storage_key,
|
||||
userId,
|
||||
documentId,
|
||||
storageKey: existing.storageKey,
|
||||
error: e instanceof Error ? e.message : 'Unknown error',
|
||||
});
|
||||
// Non-fatal: proceed with soft delete
|
||||
@@ -166,10 +166,10 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document deleted', {
|
||||
operation: 'documents.delete.success',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
vehicle_id: existing?.vehicle_id,
|
||||
had_file: !!(existing?.storage_key),
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId: existing?.vehicleId,
|
||||
hadFile: !!(existing?.storageKey),
|
||||
});
|
||||
|
||||
return reply.code(204).send();
|
||||
@@ -181,16 +181,16 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document upload requested', {
|
||||
operation: 'documents.upload',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
|
||||
const doc = await this.service.getDocument(userId, documentId);
|
||||
if (!doc) {
|
||||
logger.warn('Document not found for upload', {
|
||||
operation: 'documents.upload.not_found',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
return reply.code(404).send({ error: 'Not Found' });
|
||||
}
|
||||
@@ -199,8 +199,8 @@ export class DocumentsController {
|
||||
if (!mp) {
|
||||
logger.warn('No file provided for upload', {
|
||||
operation: 'documents.upload.no_file',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
return reply.code(400).send({ error: 'Bad Request', message: 'No file provided' });
|
||||
}
|
||||
@@ -216,10 +216,10 @@ export class DocumentsController {
|
||||
if (!contentType || !allowedTypes.has(contentType)) {
|
||||
logger.warn('Unsupported file type for upload (header validation)', {
|
||||
operation: 'documents.upload.unsupported_type',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
content_type: contentType,
|
||||
file_name: mp.filename,
|
||||
userId,
|
||||
documentId,
|
||||
contentType,
|
||||
fileName: mp.filename,
|
||||
});
|
||||
return reply.code(415).send({
|
||||
error: 'Unsupported Media Type',
|
||||
@@ -248,10 +248,10 @@ export class DocumentsController {
|
||||
if (!detectedType) {
|
||||
logger.warn('Unable to detect file type from content', {
|
||||
operation: 'documents.upload.type_detection_failed',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
content_type: contentType,
|
||||
file_name: mp.filename,
|
||||
userId,
|
||||
documentId,
|
||||
contentType,
|
||||
fileName: mp.filename,
|
||||
});
|
||||
return reply.code(415).send({
|
||||
error: 'Unsupported Media Type',
|
||||
@@ -264,11 +264,11 @@ export class DocumentsController {
|
||||
if (!allowedDetectedTypes || !allowedDetectedTypes.has(detectedType.mime)) {
|
||||
logger.warn('File content does not match Content-Type header', {
|
||||
operation: 'documents.upload.type_mismatch',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
claimed_type: contentType,
|
||||
detected_type: detectedType.mime,
|
||||
file_name: mp.filename,
|
||||
userId,
|
||||
documentId,
|
||||
claimedType: contentType,
|
||||
detectedType: detectedType.mime,
|
||||
fileName: mp.filename,
|
||||
});
|
||||
return reply.code(415).send({
|
||||
error: 'Unsupported Media Type',
|
||||
@@ -310,29 +310,29 @@ export class DocumentsController {
|
||||
const bucket = 'documents';
|
||||
const version = 'v1';
|
||||
const unique = cryptoRandom();
|
||||
const key = `documents/${userId}/${doc.vehicle_id}/${doc.id}/${version}/${unique}.${ext}`;
|
||||
const key = `documents/${userId}/${doc.vehicleId}/${doc.id}/${version}/${unique}.${ext}`;
|
||||
|
||||
await storage.putObject(bucket, key, counter, contentType, { 'x-original-filename': originalName });
|
||||
|
||||
const updated = await this.service['repo'].updateStorageMeta(doc.id, userId, {
|
||||
storage_bucket: bucket,
|
||||
storage_key: key,
|
||||
file_name: originalName,
|
||||
content_type: contentType,
|
||||
file_size: counter.bytes,
|
||||
file_hash: null,
|
||||
storageBucket: bucket,
|
||||
storageKey: key,
|
||||
fileName: originalName,
|
||||
contentType: contentType,
|
||||
fileSize: counter.bytes,
|
||||
fileHash: null,
|
||||
});
|
||||
|
||||
logger.info('Document upload completed', {
|
||||
operation: 'documents.upload.success',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
vehicle_id: doc.vehicle_id,
|
||||
file_name: originalName,
|
||||
content_type: contentType,
|
||||
detected_type: detectedType.mime,
|
||||
file_size: counter.bytes,
|
||||
storage_key: key,
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId: doc.vehicleId,
|
||||
fileName: originalName,
|
||||
contentType,
|
||||
detectedType: detectedType.mime,
|
||||
fileSize: counter.bytes,
|
||||
storageKey: key,
|
||||
});
|
||||
|
||||
return reply.code(200).send(updated);
|
||||
@@ -344,18 +344,18 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document download requested', {
|
||||
operation: 'documents.download',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
|
||||
const doc = await this.service.getDocument(userId, documentId);
|
||||
if (!doc || !doc.storage_bucket || !doc.storage_key) {
|
||||
if (!doc || !doc.storageBucket || !doc.storageKey) {
|
||||
logger.warn('Document or file not found for download', {
|
||||
operation: 'documents.download.not_found',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
has_document: !!doc,
|
||||
has_storage_info: !!(doc?.storage_bucket && doc?.storage_key),
|
||||
userId,
|
||||
documentId,
|
||||
hasDocument: !!doc,
|
||||
hasStorageInfo: !!(doc?.storageBucket && doc?.storageKey),
|
||||
});
|
||||
return reply.code(404).send({ error: 'Not Found' });
|
||||
}
|
||||
@@ -363,10 +363,10 @@ export class DocumentsController {
|
||||
const storage = getStorageService();
|
||||
let head: Partial<import('../../../core/storage/storage.service').HeadObjectResult> = {};
|
||||
try {
|
||||
head = await storage.headObject(doc.storage_bucket, doc.storage_key);
|
||||
head = await storage.headObject(doc.storageBucket, doc.storageKey);
|
||||
} catch { /* ignore */ }
|
||||
const contentType = head.contentType || doc.content_type || 'application/octet-stream';
|
||||
const filename = doc.file_name || path.basename(doc.storage_key);
|
||||
const contentType = head.contentType || doc.contentType || 'application/octet-stream';
|
||||
const filename = doc.fileName || path.basename(doc.storageKey);
|
||||
const inlineTypes = new Set(['application/pdf', 'image/jpeg', 'image/png']);
|
||||
const disposition = inlineTypes.has(contentType) ? 'inline' : 'attachment';
|
||||
|
||||
@@ -375,16 +375,16 @@ export class DocumentsController {
|
||||
|
||||
logger.info('Document download initiated', {
|
||||
operation: 'documents.download.success',
|
||||
user_id: userId,
|
||||
document_id: documentId,
|
||||
vehicle_id: doc.vehicle_id,
|
||||
file_name: filename,
|
||||
content_type: contentType,
|
||||
disposition: disposition,
|
||||
file_size: head.size || doc.file_size,
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId: doc.vehicleId,
|
||||
fileName: filename,
|
||||
contentType,
|
||||
disposition,
|
||||
fileSize: head.size || doc.fileSize,
|
||||
});
|
||||
|
||||
const stream = await storage.getObjectStream(doc.storage_bucket, doc.storage_key);
|
||||
const stream = await storage.getObjectStream(doc.storageBucket, doc.storageKey);
|
||||
return reply.send(stream);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user