Merge pull request 'feat: Document feature enhancements (#31)' (#32) from issue-31-document-enhancements into main
All checks were successful
Deploy to Staging / Build Images (push) Successful in 4m43s
Deploy to Staging / Deploy to Staging (push) Successful in 38s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
All checks were successful
Deploy to Staging / Build Images (push) Successful in 4m43s
Deploy to Staging / Deploy to Staging (push) Successful in 38s
Deploy to Staging / Verify Staging (push) Successful in 7s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Reviewed-on: #32
This commit was merged in pull request #32.
This commit is contained in:
@@ -421,6 +421,165 @@ export class DocumentsController {
|
||||
const stream = await storage.getObjectStream(doc.storageBucket, doc.storageKey);
|
||||
return reply.send(stream);
|
||||
}
|
||||
|
||||
async listByVehicle(request: FastifyRequest<{ Params: { vehicleId: string } }>, reply: FastifyReply) {
|
||||
const userId = (request as any).user?.sub as string;
|
||||
const vehicleId = request.params.vehicleId;
|
||||
|
||||
logger.info('Documents by vehicle requested', {
|
||||
operation: 'documents.listByVehicle',
|
||||
userId,
|
||||
vehicleId,
|
||||
});
|
||||
|
||||
try {
|
||||
const docs = await this.service.getDocumentsByVehicle(userId, vehicleId);
|
||||
|
||||
logger.info('Documents by vehicle retrieved', {
|
||||
operation: 'documents.listByVehicle.success',
|
||||
userId,
|
||||
vehicleId,
|
||||
documentCount: docs.length,
|
||||
});
|
||||
|
||||
return reply.code(200).send(docs);
|
||||
} catch (e: any) {
|
||||
if (e.statusCode === 403) {
|
||||
logger.warn('Vehicle not found or not owned', {
|
||||
operation: 'documents.listByVehicle.forbidden',
|
||||
userId,
|
||||
vehicleId,
|
||||
});
|
||||
return reply.code(403).send({ error: 'Forbidden', message: e.message });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async addVehicle(request: FastifyRequest<{ Params: { id: string; vehicleId: string } }>, reply: FastifyReply) {
|
||||
const userId = (request as any).user?.sub as string;
|
||||
const { id: documentId, vehicleId } = request.params;
|
||||
|
||||
logger.info('Add vehicle to document requested', {
|
||||
operation: 'documents.addVehicle',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
|
||||
try {
|
||||
const updated = await this.service.addVehicleToDocument(userId, documentId, vehicleId);
|
||||
|
||||
if (!updated) {
|
||||
logger.warn('Document not updated (possibly duplicate vehicle)', {
|
||||
operation: 'documents.addVehicle.not_updated',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
return reply.code(400).send({ error: 'Bad Request', message: 'Vehicle could not be added' });
|
||||
}
|
||||
|
||||
logger.info('Vehicle added to document', {
|
||||
operation: 'documents.addVehicle.success',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
sharedVehicleCount: updated.sharedVehicleIds.length,
|
||||
});
|
||||
|
||||
return reply.code(200).send(updated);
|
||||
} catch (e: any) {
|
||||
if (e.statusCode === 404) {
|
||||
logger.warn('Document not found for adding vehicle', {
|
||||
operation: 'documents.addVehicle.not_found',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
return reply.code(404).send({ error: 'Not Found', message: e.message });
|
||||
}
|
||||
if (e.statusCode === 400) {
|
||||
logger.warn('Bad request for adding vehicle', {
|
||||
operation: 'documents.addVehicle.bad_request',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
reason: e.message,
|
||||
});
|
||||
return reply.code(400).send({ error: 'Bad Request', message: e.message });
|
||||
}
|
||||
if (e.statusCode === 403) {
|
||||
logger.warn('Forbidden - vehicle not owned', {
|
||||
operation: 'documents.addVehicle.forbidden',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
return reply.code(403).send({ error: 'Forbidden', message: e.message });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async removeVehicle(request: FastifyRequest<{ Params: { id: string; vehicleId: string } }>, reply: FastifyReply) {
|
||||
const userId = (request as any).user?.sub as string;
|
||||
const { id: documentId, vehicleId } = request.params;
|
||||
|
||||
logger.info('Remove vehicle from document requested', {
|
||||
operation: 'documents.removeVehicle',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
|
||||
try {
|
||||
const updated = await this.service.removeVehicleFromDocument(userId, documentId, vehicleId);
|
||||
|
||||
if (!updated) {
|
||||
// Document was soft deleted
|
||||
logger.info('Document soft deleted (primary vehicle removed, no shared vehicles)', {
|
||||
operation: 'documents.removeVehicle.deleted',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
return reply.code(204).send();
|
||||
}
|
||||
|
||||
logger.info('Vehicle removed from document', {
|
||||
operation: 'documents.removeVehicle.success',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
sharedVehicleCount: updated.sharedVehicleIds.length,
|
||||
primaryVehicleId: updated.vehicleId,
|
||||
});
|
||||
|
||||
return reply.code(200).send(updated);
|
||||
} catch (e: any) {
|
||||
if (e.statusCode === 404) {
|
||||
logger.warn('Document not found for removing vehicle', {
|
||||
operation: 'documents.removeVehicle.not_found',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
});
|
||||
return reply.code(404).send({ error: 'Not Found', message: e.message });
|
||||
}
|
||||
if (e.statusCode === 400) {
|
||||
logger.warn('Bad request for removing vehicle', {
|
||||
operation: 'documents.removeVehicle.bad_request',
|
||||
userId,
|
||||
documentId,
|
||||
vehicleId,
|
||||
reason: e.message,
|
||||
});
|
||||
return reply.code(400).send({ error: 'Bad Request', message: e.message });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cryptoRandom(): string {
|
||||
|
||||
Reference in New Issue
Block a user