refactor(documents): mutualized organization and document validation logic (#18)

This commit is contained in:
Corentin THOMASSET
2025-01-07 01:00:33 +01:00
committed by GitHub
parent c00b2b5bbd
commit 60d4028aa8
5 changed files with 68 additions and 56 deletions
@@ -0,0 +1,7 @@
import { createErrorFactory } from '../shared/errors/errors';
export const createDocumentNotFoundError = createErrorFactory({
message: 'Document not found.',
code: 'document.not_found',
statusCode: 404,
});
@@ -6,10 +6,11 @@ import { getDb } from '../app/database/database.models';
import { getConfig } from '../config/config.models';
import { organizationIdRegex } from '../organizations/organizations.constants';
import { createOrganizationsRepository } from '../organizations/organizations.repository';
import { ensureUserIsInOrganization } from '../organizations/organizations.usecases';
import { createError } from '../shared/errors/errors';
import { validateFormData, validateParams, validateQuery } from '../shared/validation/validation';
import { createDocumentsRepository } from './documents.repository';
import { createDocument } from './documents.usecases';
import { createDocument, ensureDocumentExists, getDocumentOrThrow } from './documents.usecases';
import { createDocumentStorageService } from './storage/documents.storage.services';
export function registerDocumentsPrivateRoutes({ app }: { app: ServerInstance }) {
@@ -113,15 +114,7 @@ function setupGetDocumentsRoute({ app }: { app: ServerInstance }) {
const documentsRepository = createDocumentsRepository({ db });
const organizationsRepository = createOrganizationsRepository({ db });
const { isInOrganization } = await organizationsRepository.isUserInOrganization({ userId, organizationId });
if (!isInOrganization) {
throw createError({
message: 'You are not part of this organization.',
code: 'user.not_in_organization',
statusCode: 403,
});
}
await ensureUserIsInOrganization({ userId, organizationId, organizationsRepository });
const [
{ documents },
@@ -155,17 +148,9 @@ function setupGetDocumentRoute({ app }: { app: ServerInstance }) {
const documentsRepository = createDocumentsRepository({ db });
const organizationsRepository = createOrganizationsRepository({ db });
const { isInOrganization } = await organizationsRepository.isUserInOrganization({ userId, organizationId });
await ensureUserIsInOrganization({ userId, organizationId, organizationsRepository });
if (!isInOrganization) {
throw createError({
message: 'You are not part of this organization.',
code: 'user.not_in_organization',
statusCode: 403,
});
}
const { document } = await documentsRepository.getDocumentById({ documentId });
const { document } = await getDocumentOrThrow({ documentId, documentsRepository });
return context.json({
document,
@@ -190,15 +175,8 @@ function setupDeleteDocumentRoute({ app }: { app: ServerInstance }) {
const documentsRepository = createDocumentsRepository({ db });
const organizationsRepository = createOrganizationsRepository({ db });
const { isInOrganization } = await organizationsRepository.isUserInOrganization({ userId, organizationId });
if (!isInOrganization) {
throw createError({
message: 'You are not part of this organization.',
code: 'user.not_in_organization',
statusCode: 403,
});
}
await ensureUserIsInOrganization({ userId, organizationId, organizationsRepository });
await ensureDocumentExists({ documentId, documentsRepository });
await documentsRepository.softDeleteDocument({ documentId, userId });
@@ -226,25 +204,9 @@ function setupGetDocumentFileRoute({ app }: { app: ServerInstance }) {
const documentsRepository = createDocumentsRepository({ db });
const organizationsRepository = createOrganizationsRepository({ db });
const { isInOrganization } = await organizationsRepository.isUserInOrganization({ userId, organizationId });
await ensureUserIsInOrganization({ userId, organizationId, organizationsRepository });
if (!isInOrganization) {
throw createError({
message: 'You are not part of this organization.',
code: 'user.not_in_organization',
statusCode: 403,
});
}
const { document } = await documentsRepository.getDocumentById({ documentId });
if (!document) {
throw createError({
message: 'Document not found.',
code: 'document.not_found',
statusCode: 404,
});
}
const { document } = await getDocumentOrThrow({ documentId, documentsRepository });
const documentsStorageService = await createDocumentStorageService({ config });
@@ -285,15 +247,7 @@ function setupSearchDocumentsRoute({ app }: { app: ServerInstance }) {
const documentsRepository = createDocumentsRepository({ db });
const organizationsRepository = createOrganizationsRepository({ db });
const { isInOrganization } = await organizationsRepository.isUserInOrganization({ userId, organizationId });
if (!isInOrganization) {
throw createError({
message: 'You are not part of this organization.',
code: 'user.not_in_organization',
statusCode: 403,
});
}
await ensureUserIsInOrganization({ userId, organizationId, organizationsRepository });
const { documents } = await documentsRepository.searchOrganizationDocuments({ organizationId, searchQuery, pageIndex, pageSize });
@@ -1,5 +1,6 @@
import type { DocumentsRepository } from './documents.repository';
import type { DocumentStorageService } from './storage/documents.storage.services';
import { createDocumentNotFoundError } from './documents.errors';
import { buildOriginalDocumentKey, generateDocumentId as generateDocumentIdImpl } from './documents.models';
export async function createDocument({
@@ -49,3 +50,29 @@ export async function createDocument({
return { document };
}
export async function getDocumentOrThrow({
documentId,
documentsRepository,
}: {
documentId: string;
documentsRepository: DocumentsRepository;
}) {
const { document } = await documentsRepository.getDocumentById({ documentId });
if (!document) {
throw createDocumentNotFoundError();
}
return { document };
}
export async function ensureDocumentExists({
documentId,
documentsRepository,
}: {
documentId: string;
documentsRepository: DocumentsRepository;
}) {
await getDocumentOrThrow({ documentId, documentsRepository });
}
@@ -0,0 +1,7 @@
import { createErrorFactory } from '../shared/errors/errors';
export const createUserNotInOrganizationError = createErrorFactory({
message: 'You are not part of this organization.',
code: 'user.not_in_organization',
statusCode: 403,
});
@@ -1,5 +1,6 @@
import type { OrganizationsRepository } from './organizations.repository';
import { ORGANIZATION_ROLE_OWNER } from './organizations.constants';
import { createUserNotInOrganizationError } from './organizations.errors';
export async function createOrganization({ name, userId, organizationsRepository }: { name: string; userId: string; organizationsRepository: OrganizationsRepository }) {
const { organization } = await organizationsRepository.saveOrganization({ organization: { name } });
@@ -8,3 +9,19 @@ export async function createOrganization({ name, userId, organizationsRepository
return { organization };
}
export async function ensureUserIsInOrganization({
userId,
organizationId,
organizationsRepository,
}: {
userId: string;
organizationId: string;
organizationsRepository: OrganizationsRepository;
}) {
const { isInOrganization } = await organizationsRepository.isUserInOrganization({ userId, organizationId });
if (!isInOrganization) {
throw createUserNotInOrganizationError();
}
}