feat: link and unlink document to resource model

This commit is contained in:
Ahmed Bouhuolia
2024-05-24 19:50:06 +02:00
parent c8f31f33be
commit 8f904fae3a
14 changed files with 347 additions and 20 deletions

View File

@@ -3,6 +3,8 @@ import { UploadDocument } from './UploadDocument';
import { DeleteAttachment } from './DeleteAttachment';
import { GetAttachment } from './GetAttachment';
import { AttachmentUploadPipeline } from './S3UploadPipeline';
import { LinkAttachment } from './LinkAttachment';
import { UnlinkAttachment } from './UnlinkAttachment';
@Service()
export class AttachmentsApplication {
@@ -15,18 +17,25 @@ export class AttachmentsApplication {
@Inject()
private getDocumentService: GetAttachment;
@Inject()
private uploadPipelineService: AttachmentUploadPipeline;
@Inject()
private linkDocumentService: LinkAttachment;
@Inject()
private unlinkDocumentService: UnlinkAttachment;
/**
*
* @returns
*
* @returns
*/
get uploadPipeline() {
return this.uploadPipelineService.uploadPipeline();
}
/**
*
* Uploads
* @param {number} tenantId
* @param {} file
* @returns
@@ -53,4 +62,43 @@ export class AttachmentsApplication {
public get(tenantId: number, documentKey: string) {
return this.getDocumentService.getAttachment(tenantId, documentKey);
}
/**
* Links the given document to resource model.
* @param {number} tenantId
* @param {string} filekey
* @param {string} modelRef
* @param {number} modelId
* @returns
*/
public link(
tenantId: number,
filekey: string,
modelRef: string,
modelId: number
) {
return this.linkDocumentService.link(tenantId, filekey, modelRef, modelId);
}
/**
* Unlinks the given document from resource model.
* @param {number} tenantId
* @param {string} filekey
* @param {string} modelRef
* @param {number} modelId
* @returns
*/
public unlink(
tenantId: number,
filekey: string,
modelRef: string,
modelId: number
) {
return this.unlinkDocumentService.unlink(
tenantId,
filekey,
modelRef,
modelId
);
}
}

View File

@@ -1,19 +1,35 @@
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
import { s3 } from '@/lib/S3/S3';
import { Service } from 'typedi';
import { Inject, Service } from 'typedi';
import HasTenancyService from '../Tenancy/TenancyService';
@Service()
export class DeleteAttachment {
@Inject()
private tenancy: HasTenancyService;
/**
* Deletes the give file attachment file key.
* @param {number} tenantId
* @param {string} filekey
*/
async delete(tenantId: number, filekey: string): Promise<void> {
const { Document, DocumentLink } = this.tenancy.models(tenantId);
const params = {
Bucket: process.env.AWS_BUCKET,
Key: filekey,
};
await s3.send(new DeleteObjectCommand(params));
const foundDocument = await Document.query()
.findOne('key', filekey)
.throwIfNotFound();
// Delete all document links
await DocumentLink.query().where('documentId', foundDocument.id).delete();
// Delete thedocument.
await Document.query().findById(foundDocument.id).delete();
}
}

View File

@@ -0,0 +1,49 @@
import { Inject, Service } from 'typedi';
import {
validateLinkModelEntryExists,
validateLinkModelExists,
} from './_utils';
import HasTenancyService from '../Tenancy/TenancyService';
import { ServiceError } from '@/exceptions';
@Service()
export class LinkAttachment {
@Inject()
private tenancy: HasTenancyService;
/**
*
* @param {number} tenantId
* @param {string} filekey
* @param {string} modelRef
* @param {number} modelId
*/
async link(
tenantId: number,
filekey: string,
modelRef: string,
modelId: number
) {
const { DocumentLink, Document, ...models } = this.tenancy.models(tenantId);
const LinkModel = models[modelRef];
validateLinkModelExists(LinkModel);
const foundLinkModel = await LinkModel.query().findById(modelId);
validateLinkModelEntryExists(foundLinkModel);
const foundLinks = await DocumentLink.query()
.where('modelRef', modelRef)
.where('modelId', modelId);
if (foundLinks.length > 0) {
throw new ServiceError('');
}
const foundFile = await Document.query().findOne('key', filekey);
await DocumentLink.query().insert({
modelRef,
modelId,
documentId: foundFile.id,
});
}
}

View File

@@ -0,0 +1,39 @@
import { Inject, Service } from 'typedi';
import HasTenancyService from '../Tenancy/TenancyService';
import {
validateLinkModelEntryExists,
validateLinkModelExists,
} from './_utils';
@Service()
export class UnlinkAttachment {
@Inject()
private tenancy: HasTenancyService;
/**
*
* @param {number} tenantId
* @param {string} filekey
* @param {string} modelRef
* @param {number} modelId
*/
async unlink(
tenantId: number,
filekey: string,
modelRef: string,
modelId: number
) {
const { DocumentLink, ...models } = this.tenancy.models(tenantId);
const LinkModel = models[modelRef];
validateLinkModelExists(LinkModel);
const foundLinkModel = await LinkModel.query().findById(modelId);
validateLinkModelEntryExists(foundLinkModel);
// Delete the document link.
await DocumentLink.query()
.where('modelRef', modelRef)
.where('modelId', modelId)
.delete();
}
}

View File

@@ -1,10 +1,18 @@
import { Service } from 'typedi';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { Inject, Service } from 'typedi';
import HasTenancyService from '../Tenancy/TenancyService';
@Service()
export class UploadDocument {
@Inject()
private tenancy: HasTenancyService;
async upload(tenantId: number, file: any) {
const { Document } = this.tenancy.models(tenantId);
const insertedDocument = await Document.query().insert({
key: file.key,
extension: file.mimetype,
});
return insertedDocument;
}
}

View File

@@ -0,0 +1,14 @@
import { ServiceError } from '@/exceptions';
import { ERRORS } from './constants';
export const validateLinkModelExists = (LinkModel) => {
if (!LinkModel) {
throw new ServiceError(ERRORS.DOCUMENT_LINK_REF_INVALID);
}
};
export const validateLinkModelEntryExists = (foundLinkModel) => {
if (!foundLinkModel) {
throw new ServiceError(ERRORS.DOCUMENT_LINK_ID_INVALID);
}
};

View File

@@ -0,0 +1,4 @@
export enum ERRORS {
DOCUMENT_LINK_REF_INVALID = 'DOCUMENT_LINK_REF_INVALID',
DOCUMENT_LINK_ID_INVALID = 'DOCUMENT_LINK_ID_INVALID',
}