Skip to content

Commit

Permalink
feat(backend): add updating organizations endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati365 committed Sep 28, 2024
1 parent f5d689f commit 6955f39
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {
type OrganizationsSdk,
SdkCreateOrganizationInputV,
SdKSearchOrganizationsInputV,
SdkUpdateOrganizationInputV,
} from '@llm/sdk';
import { ConfigService } from '~/modules/config';
import { OrganizationsService } from '~/modules/organizations';

import {
rejectUnsafeCreateSdkErrors,
mapDbRecordAlreadyExistsToSdkError,
mapDbRecordNotFoundToSdkError,
rejectUnsafeSdkErrors,
sdkSchemaValidator,
serializeSdkResponseTE,
Expand All @@ -37,15 +39,30 @@ export class OrganizationsController extends AuthorizedController {
),
)
.post(
'/create',
'/',
sdkSchemaValidator('json', SdkCreateOrganizationInputV),
async context => pipe(
context.req.valid('json'),
organizationsService.asUser(context.var.jwt).create,
rejectUnsafeCreateSdkErrors,
mapDbRecordAlreadyExistsToSdkError,
rejectUnsafeSdkErrors,
serializeSdkResponseTE<ReturnType<OrganizationsSdk['create']>>(context),
),
)
.put(
'/:id',
sdkSchemaValidator('json', SdkUpdateOrganizationInputV),
async context => pipe(
{
id: Number(context.req.param().id),
...context.req.valid('json'),
},
organizationsService.asUser(context.var.jwt).update,
mapDbRecordAlreadyExistsToSdkError,
mapDbRecordNotFoundToSdkError,
rejectUnsafeSdkErrors,
serializeSdkResponseTE<ReturnType<OrganizationsSdk['update']>>(context),
),
);
}
}
2 changes: 1 addition & 1 deletion apps/backend/src/modules/api/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './reject-unsafe-create-sdk-errors';
export * from './map-tag-to-sdk-errors';
export * from './reject-unsafe-sdk-errors';
export * from './respond-with-tagged-error';
export * from './sdk-hono-schema-validator';
Expand Down
44 changes: 44 additions & 0 deletions apps/backend/src/modules/api/helpers/map-tag-to-sdk-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { taskEither as TE } from 'fp-ts';
import { pipe } from 'fp-ts/function';

import type { TaggedError } from '@llm/commons';

import { isSdkTaggedError, SdkRecordAlreadyExistsError, SdkRecordNotFoundError } from '@llm/sdk';
import { DatabaseRecordAlreadyExists, DatabaseRecordNotExists } from '~/modules/database';
import { LoggerService } from '~/modules/logger';

export function mapTagToSdkError<const ET extends string, RET extends TaggedError<`Sdk${string}`>>(
catchTag: ET,
mapper: (err: TaggedError<string>) => RET,
) {
const logger = LoggerService.of('mapTagToSdkError');

return <T, E extends TaggedError<string, any>>(task: TE.TaskEither<E, T>) => pipe(
task,
TE.mapLeft((error) => {
if (isSdkTaggedError(error) || error.tag !== catchTag) {
return error;
}

const { stack, ...context } = error;

logger.error(`Mapped creator SDK error - ${error.tag}!`, context);

if (stack) {
console.error(stack);
}

return mapper(error);
}),
) as TE.TaskEither<Exclude<E, TaggedError<ET>> | RET, T>;
}

export const mapDbRecordAlreadyExistsToSdkError = mapTagToSdkError(
DatabaseRecordAlreadyExists.tag,
() => new SdkRecordAlreadyExistsError({}),
);

export const mapDbRecordNotFoundToSdkError = mapTagToSdkError(
DatabaseRecordNotExists.tag,
() => new SdkRecordNotFoundError({}),
);

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TaggedError } from '@llm/commons';

export class DatabaseRecordAlreadyExists extends TaggedError.ofLiteral()('DatabaseRecordAlreadyExists') {}
export class DatabaseRecordAlreadyExists extends TaggedError.ofLiteral()('DatabaseRecordAlreadyExists') {
readonly httpCode = 403;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TaggedError } from '@llm/commons';

export class DatabaseRecordNotExists extends TaggedError.ofLiteral()('DatabaseRecordNotExists') {}
export class DatabaseRecordNotExists extends TaggedError.ofLiteral()('DatabaseRecordNotExists') {
readonly httpCode = 404;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export class OrganizationsFirewall extends AuthFirewallService {
super(jwt);
}

update = flow(
this.organizationsService.update,
this.tryTEIfUser.is.root,
);

create = flow(
this.organizationsService.create,
this.tryTEIfUser.is.root,
Expand Down
12 changes: 11 additions & 1 deletion apps/backend/src/modules/organizations/organizations.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { pipe } from 'fp-ts/function';
import { inject, injectable } from 'tsyringe';

import type { SdkCreateOrganizationInputT, SdkJwtTokenT } from '@llm/sdk';
import type {
SdkCreateOrganizationInputT,
SdkJwtTokenT,
SdkUpdateOrganizationInputT,
} from '@llm/sdk';

import { tapTaskEitherTE } from '@llm/commons';

import type { WithAuthFirewall } from '../auth';
import type { TableRowWithId } from '../database';

import { OrganizationsEsIndexRepo } from './elasticsearch';
import { OrganizationsEsSearchRepo } from './elasticsearch/organizations-es-search.repo';
Expand All @@ -27,5 +32,10 @@ export class OrganizationsService implements WithAuthFirewall<OrganizationsFirew
tapTaskEitherTE(({ id }) => this.esIndexRepo.findAndIndexDocumentById(id)),
);

update = ({ id, ...value }: SdkUpdateOrganizationInputT & TableRowWithId) => pipe(
this.repo.update({ id, value }),
tapTaskEitherTE(() => this.esIndexRepo.findAndIndexDocumentById(id)),
);

asUser = (jwt: SdkJwtTokenT) => new OrganizationsFirewall(jwt, this);
}
2 changes: 2 additions & 0 deletions packages/commons/src/errors/tagged-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export abstract class TaggedError<
static ofLiteral<C extends object>() {
return <const S extends string>(tag: S) =>
class TaggedLiteralError extends TaggedError<S, C> {
static readonly tag = tag;

readonly tag = tag;
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './sdk-create-organization-user.dto';
export * from './sdk-organization.dto';
export * from './sdk-organization-user.dto';
export * from './sdk-search-organizations.dto';
export * from './sdk-update-organization.dto';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { z } from 'zod';

import { SdkTableRowWithIdV, ZodOmitArchivedFields, ZodOmitDateFields } from '~/shared';

import { SdkOrganizationV } from './sdk-organization.dto';

export const SdkUpdateOrganizationInputV = SdkOrganizationV.omit({
...ZodOmitDateFields,
...ZodOmitArchivedFields,
id: true,
});

export type SdkUpdateOrganizationInputT = z.infer<typeof SdkUpdateOrganizationInputV>;

export const SdkUpdateOrganizationOutputV = SdkTableRowWithIdV;

export type SdkUpdateOrganizationOutputT = z.infer<typeof SdkUpdateOrganizationOutputV>;
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import {
getPayload,
performApiRequest,
postPayload,
putPayload,
type SdkRecordAlreadyExistsError,
type SdkRecordNotFoundError,
type SdkTableRowWithIdT,
} from '~/shared';

import type {
SdkCreateOrganizationInputT,
SdkCreateOrganizationOutputT,
SdKSearchOrganizationsInputT,
SdKSearchOrganizationsOutputT,
SdkUpdateOrganizationInputT,
SdkUpdateOrganizationOutputT,
} from './dto';

export class OrganizationsSdk extends AbstractNestedSdkWithAuth {
Expand All @@ -25,7 +30,16 @@ export class OrganizationsSdk extends AbstractNestedSdkWithAuth {

create = (data: SdkCreateOrganizationInputT) =>
performApiRequest<SdkCreateOrganizationOutputT, SdkRecordAlreadyExistsError>({
url: this.endpoint('/create'),
url: this.endpoint('/'),
options: postPayload(data),
});

update = ({ id, ...data }: SdkUpdateOrganizationInputT & SdkTableRowWithIdT) =>
performApiRequest<
SdkUpdateOrganizationOutputT,
SdkRecordAlreadyExistsError | SdkRecordNotFoundError
>({
url: this.endpoint(`/${id}`),
options: putPayload(data),
});
};
1 change: 1 addition & 0 deletions packages/sdk/src/shared/errors/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './is-sdk-tagged-error';
export * from './sdk-payload-validation.error';
export * from './sdk-record-already-exists.error';
export * from './sdk-record-not-found.error';
export * from './sdk-request.error';
export * from './sdk-server.error';
export * from './sdk-unauthorized.error';
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TaggedError } from '@llm/commons';

export class SdkRecordAlreadyExistsError extends TaggedError.ofLiteral()('SdkRecordAlreadyExistsError') {}
export class SdkRecordAlreadyExistsError extends TaggedError.ofLiteral()('SdkRecordAlreadyExistsError') {
static readonly httpCode = 403;
}
5 changes: 5 additions & 0 deletions packages/sdk/src/shared/errors/sdk-record-not-found.error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { TaggedError } from '@llm/commons';

export class SdkRecordNotFoundError extends TaggedError.ofLiteral()('SdkRecordNotFoundError') {
readonly httpCode = 404;
}

0 comments on commit 6955f39

Please sign in to comment.