feat: Dynamic hook registration for WorkspaceQueryHooks (#6008)
#### Overview
This PR introduces a new API for dynamically registering and executing
pre and post query hooks in the Workspace Query Hook system using the
`@WorkspaceQueryHook` decorator. This approach eliminates the need for
manual provider registration, and fix the issue of `undefined` or `null`
repository using `@InjectWorkspaceRepository`.
#### New API
**Define a Hook**
Use the `@WorkspaceQueryHook` decorator to define pre or post hooks:
```typescript
@WorkspaceQueryHook({
key: `calendarEvent.findMany`,
scope: Scope.REQUEST,
})
export class CalendarEventFindManyPreQueryHook implements WorkspaceQueryHookInstance {
async execute(userId: string, workspaceId: string, payload: FindManyResolverArgs): Promise<void> {
if (!payload?.filter?.id?.eq) {
throw new BadRequestException('id filter is required');
}
// Implement hook logic here
}
}
```
This API simplifies the registration and execution of query hooks,
providing a more flexible and maintainable approach.
---------
Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
@ -141,8 +141,10 @@ export class GraphQLConfigService
|
|||||||
// Create a new contextId for each request
|
// Create a new contextId for each request
|
||||||
const contextId = ContextIdFactory.create();
|
const contextId = ContextIdFactory.create();
|
||||||
|
|
||||||
// Register the request in the contextId
|
if (this.moduleRef.registerRequestByContextId) {
|
||||||
this.moduleRef.registerRequestByContextId(context.req, contextId);
|
// Register the request in the contextId
|
||||||
|
this.moduleRef.registerRequestByContextId(context.req, contextId);
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve the WorkspaceSchemaFactory for the contextId
|
// Resolve the WorkspaceSchemaFactory for the contextId
|
||||||
const workspaceFactory = await this.moduleRef.resolve(
|
const workspaceFactory = await this.moduleRef.resolve(
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type';
|
|
||||||
import { CalendarEventFindManyPreQueryHook } from 'src/modules/calendar/query-hooks/calendar-event/calendar-event-find-many.pre-query.hook';
|
|
||||||
import { CalendarEventFindOnePreQueryHook } from 'src/modules/calendar/query-hooks/calendar-event/calendar-event-find-one.pre-query-hook';
|
|
||||||
import { BlocklistCreateManyPreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-create-many.pre-query.hook';
|
|
||||||
import { BlocklistUpdateManyPreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-update-many.pre-query.hook';
|
|
||||||
import { BlocklistUpdateOnePreQueryHook } from 'src/modules/connected-account/query-hooks/blocklist/blocklist-update-one.pre-query.hook';
|
|
||||||
import { WorkspaceMemberDeleteOnePreQueryHook } from 'src/modules/workspace-member/query-hooks/workspace-member-delete-one.pre-query.hook';
|
|
||||||
import { WorkspaceMemberDeleteManyPreQueryHook } from 'src/modules/workspace-member/query-hooks/workspace-member-delete-many.pre-query.hook';
|
|
||||||
import { MessageFindManyPreQueryHook } from 'src/modules/messaging/common/query-hooks/message/message-find-many.pre-query.hook';
|
|
||||||
import { MessageFindOnePreQueryHook } from 'src/modules/messaging/common/query-hooks/message/message-find-one.pre-query-hook';
|
|
||||||
|
|
||||||
// TODO: move to a decorator
|
|
||||||
export const workspacePreQueryHooks: WorkspaceQueryHook = {
|
|
||||||
message: {
|
|
||||||
findOne: [MessageFindOnePreQueryHook.name],
|
|
||||||
findMany: [MessageFindManyPreQueryHook.name],
|
|
||||||
},
|
|
||||||
calendarEvent: {
|
|
||||||
findOne: [CalendarEventFindOnePreQueryHook.name],
|
|
||||||
findMany: [CalendarEventFindManyPreQueryHook.name],
|
|
||||||
},
|
|
||||||
blocklist: {
|
|
||||||
createMany: [BlocklistCreateManyPreQueryHook.name],
|
|
||||||
updateMany: [BlocklistUpdateManyPreQueryHook.name],
|
|
||||||
updateOne: [BlocklistUpdateOnePreQueryHook.name],
|
|
||||||
},
|
|
||||||
workspaceMember: {
|
|
||||||
deleteOne: [WorkspaceMemberDeleteOnePreQueryHook.name],
|
|
||||||
deleteMany: [WorkspaceMemberDeleteManyPreQueryHook.name],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { WorkspacePreQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service';
|
|
||||||
import { CalendarQueryHookModule } from 'src/modules/calendar/query-hooks/calendar-query-hook.module';
|
|
||||||
import { ConnectedAccountQueryHookModule } from 'src/modules/connected-account/query-hooks/connected-account-query-hook.module';
|
|
||||||
import { MessagingQueryHookModule } from 'src/modules/messaging/common/query-hooks/messaging-query-hook.module';
|
|
||||||
import { WorkspaceMemberQueryHookModule } from 'src/modules/workspace-member/query-hooks/workspace-member-query-hook.module';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [
|
|
||||||
MessagingQueryHookModule,
|
|
||||||
CalendarQueryHookModule,
|
|
||||||
ConnectedAccountQueryHookModule,
|
|
||||||
WorkspaceMemberQueryHookModule,
|
|
||||||
],
|
|
||||||
providers: [WorkspacePreQueryHookService],
|
|
||||||
exports: [WorkspacePreQueryHookService],
|
|
||||||
})
|
|
||||||
export class WorkspacePreQueryHookModule {}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { ModuleRef } from '@nestjs/core';
|
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
|
||||||
|
|
||||||
import {
|
|
||||||
ExecutePreHookMethod,
|
|
||||||
WorkspacePreQueryHookPayload,
|
|
||||||
} from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type';
|
|
||||||
import { workspacePreQueryHooks } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.config';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class WorkspacePreQueryHookService {
|
|
||||||
constructor(private readonly workspaceQueryHookModuleRef: ModuleRef) {}
|
|
||||||
|
|
||||||
public async executePreHooks<T extends ExecutePreHookMethod>(
|
|
||||||
userId: string | undefined,
|
|
||||||
workspaceId: string,
|
|
||||||
objectName: string,
|
|
||||||
method: T,
|
|
||||||
payload: WorkspacePreQueryHookPayload<T>,
|
|
||||||
): Promise<void> {
|
|
||||||
const hooks = workspacePreQueryHooks[objectName] || [];
|
|
||||||
|
|
||||||
for (const hookName of Object.values(hooks[method] ?? [])) {
|
|
||||||
const hook: WorkspacePreQueryHook =
|
|
||||||
await this.workspaceQueryHookModuleRef.get(hookName, {
|
|
||||||
strict: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await hook.execute(userId, workspaceId, payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { Scope, SetMetadata } from '@nestjs/common';
|
||||||
|
import { SCOPE_OPTIONS_METADATA } from '@nestjs/common/constants';
|
||||||
|
|
||||||
|
import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WORKSPACE_QUERY_HOOK_METADATA } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants';
|
||||||
|
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||||
|
|
||||||
|
export type WorkspaceQueryHookKey =
|
||||||
|
`${string}.${WorkspaceResolverBuilderMethodNames}`;
|
||||||
|
|
||||||
|
export interface WorkspaceQueryHookOptions {
|
||||||
|
key: WorkspaceQueryHookKey;
|
||||||
|
type?: WorkspaceQueryHookType;
|
||||||
|
scope?: Scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WorkspaceQueryHook(key: WorkspaceQueryHookKey): ClassDecorator;
|
||||||
|
export function WorkspaceQueryHook(
|
||||||
|
options: WorkspaceQueryHookOptions,
|
||||||
|
): ClassDecorator;
|
||||||
|
export function WorkspaceQueryHook(
|
||||||
|
keyOrOptions: WorkspaceQueryHookKey | WorkspaceQueryHookOptions,
|
||||||
|
): ClassDecorator {
|
||||||
|
const options: WorkspaceQueryHookOptions =
|
||||||
|
keyOrOptions && typeof keyOrOptions === 'object'
|
||||||
|
? keyOrOptions
|
||||||
|
: { key: keyOrOptions };
|
||||||
|
|
||||||
|
// Default to PreHook
|
||||||
|
if (!options.type) {
|
||||||
|
options.type = WorkspaceQueryHookType.PreHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
return (target: Function) => {
|
||||||
|
SetMetadata(SCOPE_OPTIONS_METADATA, options)(target);
|
||||||
|
SetMetadata(WORKSPACE_QUERY_HOOK_METADATA, options)(target);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { ResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { ResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
export interface WorkspacePreQueryHook {
|
export interface WorkspaceQueryHookInstance {
|
||||||
execute(
|
execute(
|
||||||
userId: string | undefined,
|
userId: string | undefined,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
// hook-registry.service.ts
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Module } from '@nestjs/core/injector/module';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
|
||||||
|
interface WorkspaceQueryHookData<T> {
|
||||||
|
instance: T;
|
||||||
|
host: Module;
|
||||||
|
isRequestScoped: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WorkspaceQueryHookStorage {
|
||||||
|
private preHookInstances = new Map<
|
||||||
|
WorkspaceQueryHookKey,
|
||||||
|
WorkspaceQueryHookData<WorkspaceQueryHookInstance>[]
|
||||||
|
>();
|
||||||
|
private postHookInstances = new Map<
|
||||||
|
WorkspaceQueryHookKey,
|
||||||
|
WorkspaceQueryHookData<WorkspaceQueryHookInstance>[]
|
||||||
|
>();
|
||||||
|
|
||||||
|
registerWorkspaceQueryPreHookInstance(
|
||||||
|
key: WorkspaceQueryHookKey,
|
||||||
|
data: WorkspaceQueryHookData<WorkspaceQueryHookInstance>,
|
||||||
|
) {
|
||||||
|
if (!this.preHookInstances.has(key)) {
|
||||||
|
this.preHookInstances.set(key, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preHookInstances.get(key)?.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorkspaceQueryPreHookInstances(
|
||||||
|
key: WorkspaceQueryHookKey,
|
||||||
|
): WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] | undefined {
|
||||||
|
return this.preHookInstances.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerWorkspaceQueryPostHookInstance(
|
||||||
|
key: WorkspaceQueryHookKey,
|
||||||
|
data: WorkspaceQueryHookData<WorkspaceQueryHookInstance>,
|
||||||
|
) {
|
||||||
|
if (!this.postHookInstances.has(key)) {
|
||||||
|
this.postHookInstances.set(key, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.postHookInstances.get(key)?.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorkspaceQueryPostHookInstances(
|
||||||
|
key: WorkspaceQueryHookKey,
|
||||||
|
): WorkspaceQueryHookData<WorkspaceQueryHookInstance>[] | undefined {
|
||||||
|
return this.postHookInstances.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,26 +10,10 @@ import {
|
|||||||
UpdateOneResolverArgs,
|
UpdateOneResolverArgs,
|
||||||
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
export type ExecutePreHookMethod =
|
export enum WorkspaceQueryHookType {
|
||||||
| 'createMany'
|
PreHook = 'PreHook',
|
||||||
| 'createOne'
|
PostHook = 'PostHook',
|
||||||
| 'deleteMany'
|
}
|
||||||
| 'deleteOne'
|
|
||||||
| 'findMany'
|
|
||||||
| 'findOne'
|
|
||||||
| 'findDuplicates'
|
|
||||||
| 'updateMany'
|
|
||||||
| 'updateOne';
|
|
||||||
|
|
||||||
export type ObjectName = string;
|
|
||||||
|
|
||||||
export type HookName = string;
|
|
||||||
|
|
||||||
export type WorkspaceQueryHook = {
|
|
||||||
[key in ObjectName]: {
|
|
||||||
[key in ExecutePreHookMethod]?: HookName[];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkspacePreQueryHookPayload<T> = T extends 'createMany'
|
export type WorkspacePreQueryHookPayload<T> = T extends 'createMany'
|
||||||
? CreateManyResolverArgs
|
? CreateManyResolverArgs
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
|
import { Injectable, Type } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
|
||||||
|
import { WORKSPACE_QUERY_HOOK_METADATA } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.constants';
|
||||||
|
import { WorkspaceQueryHookOptions } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WorkspaceQueryHookMetadataAccessor {
|
||||||
|
constructor(private readonly reflector: Reflector) {}
|
||||||
|
|
||||||
|
isWorkspaceQueryHook(target: Type<any> | Function): boolean {
|
||||||
|
if (!target) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!this.reflector.get(WORKSPACE_QUERY_HOOK_METADATA, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorkspaceQueryHookMetadata(
|
||||||
|
target: Type<any> | Function,
|
||||||
|
): WorkspaceQueryHookOptions | undefined {
|
||||||
|
return this.reflector.get(WORKSPACE_QUERY_HOOK_METADATA, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
export const WORKSPACE_QUERY_HOOK_METADATA = Symbol(
|
||||||
|
'workspace-query-hook:query-hook-metadata',
|
||||||
|
);
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { DiscoveryService, ModuleRef, createContextId } from '@nestjs/core';
|
||||||
|
import { Module } from '@nestjs/core/injector/module';
|
||||||
|
import { Injector } from '@nestjs/core/injector/injector';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHookMetadataAccessor } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor';
|
||||||
|
import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage';
|
||||||
|
import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WorkspaceQueryHookExplorer implements OnModuleInit {
|
||||||
|
private readonly logger = new Logger('WorkspaceQueryHookModule');
|
||||||
|
private readonly injector = new Injector();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly moduleRef: ModuleRef,
|
||||||
|
private readonly discoveryService: DiscoveryService,
|
||||||
|
private readonly metadataAccessor: WorkspaceQueryHookMetadataAccessor,
|
||||||
|
private readonly workspaceQueryHookStorage: WorkspaceQueryHookStorage,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
onModuleInit() {
|
||||||
|
this.explore();
|
||||||
|
}
|
||||||
|
|
||||||
|
async explore() {
|
||||||
|
const hooks = this.discoveryService
|
||||||
|
.getProviders()
|
||||||
|
.filter((wrapper) =>
|
||||||
|
this.metadataAccessor.isWorkspaceQueryHook(
|
||||||
|
!wrapper.metatype || wrapper.inject
|
||||||
|
? wrapper.instance?.constructor
|
||||||
|
: wrapper.metatype,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const hook of hooks) {
|
||||||
|
const { instance, metatype } = hook;
|
||||||
|
|
||||||
|
const { key, type } =
|
||||||
|
this.metadataAccessor.getWorkspaceQueryHookMetadata(
|
||||||
|
instance.constructor || metatype,
|
||||||
|
) ?? {};
|
||||||
|
|
||||||
|
if (!key || !type) {
|
||||||
|
this.logger.error(
|
||||||
|
`PreHook ${hook.name} is missing key or type metadata`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hook.host) {
|
||||||
|
this.logger.error(`PreHook ${hook.name} is missing host metadata`);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.registerWorkspaceQueryHook(
|
||||||
|
key,
|
||||||
|
type,
|
||||||
|
instance,
|
||||||
|
hook.host,
|
||||||
|
!hook.isDependencyTreeStatic(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleHook(
|
||||||
|
payload: Parameters<WorkspaceQueryHookInstance['execute']>,
|
||||||
|
instance: object,
|
||||||
|
host: Module,
|
||||||
|
isRequestScoped: boolean,
|
||||||
|
) {
|
||||||
|
const methodName = 'execute';
|
||||||
|
|
||||||
|
if (isRequestScoped) {
|
||||||
|
const contextId = createContextId();
|
||||||
|
|
||||||
|
if (this.moduleRef.registerRequestByContextId) {
|
||||||
|
this.moduleRef.registerRequestByContextId(
|
||||||
|
{
|
||||||
|
req: {
|
||||||
|
workspaceId: payload?.[1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
contextId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextInstance = await this.injector.loadPerContext(
|
||||||
|
instance,
|
||||||
|
host,
|
||||||
|
host.providers,
|
||||||
|
contextId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await contextInstance[methodName].call(contextInstance, ...payload);
|
||||||
|
} else {
|
||||||
|
await instance[methodName].call(instance, ...payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerWorkspaceQueryHook(
|
||||||
|
key: WorkspaceQueryHookKey,
|
||||||
|
type: WorkspaceQueryHookType,
|
||||||
|
instance: object,
|
||||||
|
host: Module,
|
||||||
|
isRequestScoped: boolean,
|
||||||
|
) {
|
||||||
|
switch (type) {
|
||||||
|
case WorkspaceQueryHookType.PreHook:
|
||||||
|
this.workspaceQueryHookStorage.registerWorkspaceQueryPreHookInstance(
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
instance: instance as WorkspaceQueryHookInstance,
|
||||||
|
host,
|
||||||
|
isRequestScoped,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case WorkspaceQueryHookType.PostHook:
|
||||||
|
this.workspaceQueryHookStorage.registerWorkspaceQueryPostHookInstance(
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
instance: instance as WorkspaceQueryHookInstance,
|
||||||
|
host,
|
||||||
|
isRequestScoped,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.logger.error(`Unknown WorkspaceQueryHookType: ${type}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { DiscoveryModule } from '@nestjs/core';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage';
|
||||||
|
import { WorkspaceQueryHookMetadataAccessor } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook-metadata.accessor';
|
||||||
|
import { WorkspaceQueryHookExplorer } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer';
|
||||||
|
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
|
||||||
|
import { CalendarQueryHookModule } from 'src/modules/calendar/query-hooks/calendar-query-hook.module';
|
||||||
|
import { ConnectedAccountQueryHookModule } from 'src/modules/connected-account/query-hooks/connected-account-query-hook.module';
|
||||||
|
import { MessagingQueryHookModule } from 'src/modules/messaging/common/query-hooks/messaging-query-hook.module';
|
||||||
|
import { WorkspaceMemberQueryHookModule } from 'src/modules/workspace-member/query-hooks/workspace-member-query-hook.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
MessagingQueryHookModule,
|
||||||
|
CalendarQueryHookModule,
|
||||||
|
ConnectedAccountQueryHookModule,
|
||||||
|
WorkspaceMemberQueryHookModule,
|
||||||
|
DiscoveryModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
WorkspaceQueryHookService,
|
||||||
|
WorkspaceQueryHookExplorer,
|
||||||
|
WorkspaceQueryHookMetadataAccessor,
|
||||||
|
WorkspaceQueryHookStorage,
|
||||||
|
],
|
||||||
|
exports: [WorkspaceQueryHookService],
|
||||||
|
})
|
||||||
|
export class WorkspaceQueryHookModule {}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHookStorage } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/storage/workspace-query-hook.storage';
|
||||||
|
import { WorkspaceQueryHookKey } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
import { WorkspaceQueryHookExplorer } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.explorer';
|
||||||
|
import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WorkspaceQueryHookService {
|
||||||
|
constructor(
|
||||||
|
private readonly workspaceQueryHookStorage: WorkspaceQueryHookStorage,
|
||||||
|
private readonly workspaceQueryHookExplorer: WorkspaceQueryHookExplorer,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async executePreQueryHooks<
|
||||||
|
T extends WorkspaceResolverBuilderMethodNames,
|
||||||
|
>(
|
||||||
|
userId: string | undefined,
|
||||||
|
workspaceId: string,
|
||||||
|
objectName: string,
|
||||||
|
methodName: T,
|
||||||
|
payload: WorkspacePreQueryHookPayload<T>,
|
||||||
|
): Promise<void> {
|
||||||
|
const key: WorkspaceQueryHookKey = `${objectName}.${methodName}`;
|
||||||
|
const preHookInstances =
|
||||||
|
this.workspaceQueryHookStorage.getWorkspaceQueryPreHookInstances(key);
|
||||||
|
|
||||||
|
if (!preHookInstances) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const preHookInstance of preHookInstances) {
|
||||||
|
await this.workspaceQueryHookExplorer.handleHook(
|
||||||
|
[userId, workspaceId, payload],
|
||||||
|
preHookInstance.instance,
|
||||||
|
preHookInstance.host,
|
||||||
|
preHookInstance.isRequestScoped,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
|
|||||||
|
|
||||||
import { WorkspaceQueryBuilderModule } from 'src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module';
|
import { WorkspaceQueryBuilderModule } from 'src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module';
|
||||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||||
import { WorkspacePreQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.module';
|
import { WorkspaceQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module';
|
||||||
import { workspaceQueryRunnerFactories } from 'src/engine/api/graphql/workspace-query-runner/factories';
|
import { workspaceQueryRunnerFactories } from 'src/engine/api/graphql/workspace-query-runner/factories';
|
||||||
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
|
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
|
||||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||||
@ -20,7 +20,7 @@ import { EntityEventsToDbListener } from './listeners/entity-events-to-db.listen
|
|||||||
AuthModule,
|
AuthModule,
|
||||||
WorkspaceQueryBuilderModule,
|
WorkspaceQueryBuilderModule,
|
||||||
WorkspaceDataSourceModule,
|
WorkspaceDataSourceModule,
|
||||||
WorkspacePreQueryHookModule,
|
WorkspaceQueryHookModule,
|
||||||
ObjectMetadataRepositoryModule.forFeature([WorkspaceMemberWorkspaceEntity]),
|
ObjectMetadataRepositoryModule.forFeature([WorkspaceMemberWorkspaceEntity]),
|
||||||
AnalyticsModule,
|
AnalyticsModule,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -42,7 +42,7 @@ import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target
|
|||||||
import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event';
|
import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event';
|
||||||
import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event';
|
import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event';
|
||||||
import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event';
|
import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event';
|
||||||
import { WorkspacePreQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service';
|
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { NotFoundError } from 'src/engine/utils/graphql-errors.util';
|
import { NotFoundError } from 'src/engine/utils/graphql-errors.util';
|
||||||
import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory';
|
import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory';
|
||||||
@ -75,7 +75,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
@InjectMessageQueue(MessageQueue.webhookQueue)
|
@InjectMessageQueue(MessageQueue.webhookQueue)
|
||||||
private readonly messageQueueService: MessageQueueService,
|
private readonly messageQueueService: MessageQueueService,
|
||||||
private readonly eventEmitter: EventEmitter2,
|
private readonly eventEmitter: EventEmitter2,
|
||||||
private readonly workspacePreQueryHookService: WorkspacePreQueryHookService,
|
private readonly workspaceQueryHookService: WorkspaceQueryHookService,
|
||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -148,7 +148,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -223,7 +223,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
existingRecord,
|
existingRecord,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -260,7 +260,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
ResolverArgsType.CreateMany,
|
ResolverArgsType.CreateMany,
|
||||||
)) as CreateManyResolverArgs<Record>;
|
)) as CreateManyResolverArgs<Record>;
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -333,7 +333,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -389,7 +389,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
atMost: maximumRecordAffected,
|
atMost: maximumRecordAffected,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -441,7 +441,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
atMost: maximumRecordAffected,
|
atMost: maximumRecordAffected,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
@ -509,7 +509,7 @@ export class WorkspaceQueryRunnerService {
|
|||||||
);
|
);
|
||||||
// TODO END
|
// TODO END
|
||||||
|
|
||||||
await this.workspacePreQueryHookService.executePreHooks(
|
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||||
userId,
|
userId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataItem.nameSingular,
|
objectMetadataItem.nameSingular,
|
||||||
|
|||||||
@ -47,10 +47,17 @@ export class PgBossDriver
|
|||||||
}
|
}
|
||||||
: {},
|
: {},
|
||||||
async (job) => {
|
async (job) => {
|
||||||
|
// PGBoss work with wildcard job name
|
||||||
|
const jobName = job.name.split('.')?.[1];
|
||||||
|
|
||||||
|
if (!jobName) {
|
||||||
|
throw new Error('Job name could not be splited from the job.');
|
||||||
|
}
|
||||||
|
|
||||||
await handler({
|
await handler({
|
||||||
data: job.data,
|
data: job.data,
|
||||||
id: job.id,
|
id: job.id,
|
||||||
name: job.name.split('.')[1],
|
name: jobName,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export class ScopedWorkspaceDatasourceFactory {
|
|||||||
|
|
||||||
public async create(entities: EntitySchema[]) {
|
public async create(entities: EntitySchema[]) {
|
||||||
const workspaceId: string | undefined =
|
const workspaceId: string | undefined =
|
||||||
this.request['req']?.['workspaceId'];
|
this.request?.['req']?.['workspaceId'];
|
||||||
|
|
||||||
if (!workspaceId) {
|
if (!workspaceId) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, NotFoundException, Scope } from '@nestjs/common';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
|
||||||
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity';
|
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity';
|
||||||
import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service';
|
import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service';
|
||||||
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
||||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook({
|
||||||
|
key: `calendarEvent.findMany`,
|
||||||
|
scope: Scope.REQUEST,
|
||||||
|
})
|
||||||
export class CalendarEventFindManyPreQueryHook
|
export class CalendarEventFindManyPreQueryHook
|
||||||
implements WorkspacePreQueryHook
|
implements WorkspaceQueryHookInstance
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity)
|
@InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity)
|
||||||
@ -27,25 +31,24 @@ export class CalendarEventFindManyPreQueryHook
|
|||||||
throw new BadRequestException('id filter is required');
|
throw new BadRequestException('id filter is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Re-implement this using twenty ORM
|
const calendarChannelCalendarEventAssociations =
|
||||||
// const calendarChannelCalendarEventAssociations =
|
await this.calendarChannelEventAssociationRepository.find({
|
||||||
// await this.calendarChannelEventAssociationRepository.find({
|
where: {
|
||||||
// where: {
|
calendarEvent: {
|
||||||
// calendarEvent: {
|
id: payload?.filter?.id?.eq,
|
||||||
// id: payload?.filter?.id?.eq,
|
},
|
||||||
// },
|
},
|
||||||
// },
|
relations: ['calendarChannel.connectedAccount'],
|
||||||
// relations: ['calendarChannel.connectedAccount'],
|
});
|
||||||
// });
|
|
||||||
|
|
||||||
// if (calendarChannelCalendarEventAssociations.length === 0) {
|
if (calendarChannelCalendarEventAssociations.length === 0) {
|
||||||
// throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// await this.canAccessCalendarEventService.canAccessCalendarEvent(
|
await this.canAccessCalendarEventService.canAccessCalendarEvent(
|
||||||
// userId,
|
userId,
|
||||||
// workspaceId,
|
workspaceId,
|
||||||
// calendarChannelCalendarEventAssociations,
|
calendarChannelCalendarEventAssociations,
|
||||||
// );
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, NotFoundException, Scope } from '@nestjs/common';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
||||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service';
|
import { CanAccessCalendarEventService } from 'src/modules/calendar/query-hooks/calendar-event/services/can-access-calendar-event.service';
|
||||||
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity';
|
import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel-event-association.workspace-entity';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook({
|
||||||
export class CalendarEventFindOnePreQueryHook implements WorkspacePreQueryHook {
|
key: `calendarEvent.findOne`,
|
||||||
|
scope: Scope.REQUEST,
|
||||||
|
})
|
||||||
|
export class CalendarEventFindOnePreQueryHook
|
||||||
|
implements WorkspaceQueryHookInstance
|
||||||
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity)
|
@InjectWorkspaceRepository(CalendarChannelEventAssociationWorkspaceEntity)
|
||||||
private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>,
|
private readonly calendarChannelEventAssociationRepository: WorkspaceRepository<CalendarChannelEventAssociationWorkspaceEntity>,
|
||||||
@ -26,23 +32,24 @@ export class CalendarEventFindOnePreQueryHook implements WorkspacePreQueryHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Re-implement this using twenty ORM
|
// TODO: Re-implement this using twenty ORM
|
||||||
// const calendarChannelCalendarEventAssociations =
|
const calendarChannelCalendarEventAssociations =
|
||||||
// await this.calendarChannelEventAssociationRepository.find({
|
await this.calendarChannelEventAssociationRepository.find({
|
||||||
// where: {
|
where: {
|
||||||
// calendarEvent: {
|
calendarEvent: {
|
||||||
// id: payload?.filter?.id?.eq,
|
id: payload?.filter?.id?.eq,
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// });
|
relations: ['calendarChannel.connectedAccount'],
|
||||||
|
});
|
||||||
|
|
||||||
// if (calendarChannelCalendarEventAssociations.length === 0) {
|
if (calendarChannelCalendarEventAssociations.length === 0) {
|
||||||
// throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// await this.canAccessCalendarEventService.canAccessCalendarEvent(
|
await this.canAccessCalendarEventService.canAccessCalendarEvent(
|
||||||
// userId,
|
userId,
|
||||||
// workspaceId,
|
workspaceId,
|
||||||
// calendarChannelCalendarEventAssociations,
|
calendarChannelCalendarEventAssociations,
|
||||||
// );
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ export class CanAccessCalendarEventService {
|
|||||||
|
|
||||||
const calendarChannelsConnectedAccounts =
|
const calendarChannelsConnectedAccounts =
|
||||||
await this.connectedAccountRepository.getByIds(
|
await this.connectedAccountRepository.getByIds(
|
||||||
calendarChannels.map((channel) => channel.connectedAccount.id),
|
calendarChannels.map((channel) => channel.connectedAccountId),
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -23,14 +23,8 @@ import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CanAccessCalendarEventService,
|
CanAccessCalendarEventService,
|
||||||
{
|
CalendarEventFindOnePreQueryHook,
|
||||||
provide: CalendarEventFindOnePreQueryHook.name,
|
CalendarEventFindManyPreQueryHook,
|
||||||
useClass: CalendarEventFindOnePreQueryHook,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: CalendarEventFindManyPreQueryHook.name,
|
|
||||||
useClass: CalendarEventFindManyPreQueryHook,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CalendarQueryHookModule {}
|
export class CalendarQueryHookModule {}
|
||||||
|
|||||||
@ -237,6 +237,8 @@ export class CalendarChannelWorkspaceEntity extends BaseWorkspaceEntity {
|
|||||||
})
|
})
|
||||||
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
|
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
|
||||||
|
|
||||||
|
connectedAccountId: string;
|
||||||
|
|
||||||
@WorkspaceRelation({
|
@WorkspaceRelation({
|
||||||
standardId:
|
standardId:
|
||||||
CALENDAR_CHANNEL_STANDARD_FIELD_IDS.calendarChannelEventAssociations,
|
CALENDAR_CHANNEL_STANDARD_FIELD_IDS.calendarChannelEventAssociations,
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
|
||||||
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import {
|
import {
|
||||||
BlocklistItem,
|
BlocklistItem,
|
||||||
BlocklistValidationService,
|
BlocklistValidationService,
|
||||||
} from 'src/modules/connected-account/services/blocklist/blocklist-validation.service';
|
} from 'src/modules/connected-account/services/blocklist/blocklist-validation.service';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook(`blocklist.createMany`)
|
||||||
export class BlocklistCreateManyPreQueryHook implements WorkspacePreQueryHook {
|
export class BlocklistCreateManyPreQueryHook
|
||||||
|
implements WorkspaceQueryHookInstance
|
||||||
|
{
|
||||||
constructor(
|
constructor(
|
||||||
private readonly blocklistValidationService: BlocklistValidationService,
|
private readonly blocklistValidationService: BlocklistValidationService,
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import { Injectable, MethodNotAllowedException } from '@nestjs/common';
|
import { MethodNotAllowedException } from '@nestjs/common';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
@Injectable()
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
export class BlocklistUpdateManyPreQueryHook implements WorkspacePreQueryHook {
|
|
||||||
|
@WorkspaceQueryHook(`blocklist.updateMany`)
|
||||||
|
export class BlocklistUpdateManyPreQueryHook
|
||||||
|
implements WorkspaceQueryHookInstance
|
||||||
|
{
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
|
||||||
import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import {
|
import {
|
||||||
BlocklistItem,
|
BlocklistItem,
|
||||||
BlocklistValidationService,
|
BlocklistValidationService,
|
||||||
} from 'src/modules/connected-account/services/blocklist/blocklist-validation.service';
|
} from 'src/modules/connected-account/services/blocklist/blocklist-validation.service';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook(`blocklist.updateOne`)
|
||||||
export class BlocklistUpdateOnePreQueryHook implements WorkspacePreQueryHook {
|
export class BlocklistUpdateOnePreQueryHook
|
||||||
|
implements WorkspaceQueryHookInstance
|
||||||
|
{
|
||||||
constructor(
|
constructor(
|
||||||
private readonly blocklistValidationService: BlocklistValidationService,
|
private readonly blocklistValidationService: BlocklistValidationService,
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@ -8,18 +8,9 @@ import { BlocklistValidationModule } from 'src/modules/connected-account/service
|
|||||||
@Module({
|
@Module({
|
||||||
imports: [BlocklistValidationModule],
|
imports: [BlocklistValidationModule],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
BlocklistCreateManyPreQueryHook,
|
||||||
provide: BlocklistCreateManyPreQueryHook.name,
|
BlocklistUpdateManyPreQueryHook,
|
||||||
useClass: BlocklistCreateManyPreQueryHook,
|
BlocklistUpdateOnePreQueryHook,
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: BlocklistUpdateManyPreQueryHook.name,
|
|
||||||
useClass: BlocklistUpdateManyPreQueryHook,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: BlocklistUpdateOnePreQueryHook.name,
|
|
||||||
useClass: BlocklistUpdateOnePreQueryHook,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ConnectedAccountQueryHookModule {}
|
export class ConnectedAccountQueryHookModule {}
|
||||||
|
|||||||
@ -1,19 +1,16 @@
|
|||||||
import {
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
BadRequestException,
|
|
||||||
Injectable,
|
|
||||||
NotFoundException,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
import { CanAccessMessageThreadService } from 'src/modules/messaging/common/query-hooks/message/can-access-message-thread.service';
|
import { CanAccessMessageThreadService } from 'src/modules/messaging/common/query-hooks/message/can-access-message-thread.service';
|
||||||
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
||||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook(`message.findMany`)
|
||||||
export class MessageFindManyPreQueryHook implements WorkspacePreQueryHook {
|
export class MessageFindManyPreQueryHook implements WorkspaceQueryHookInstance {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectObjectMetadataRepository(
|
@InjectObjectMetadataRepository(
|
||||||
MessageChannelMessageAssociationWorkspaceEntity,
|
MessageChannelMessageAssociationWorkspaceEntity,
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { NotFoundException } from '@nestjs/common';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { FindOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
|
||||||
import { CanAccessMessageThreadService } from 'src/modules/messaging/common/query-hooks/message/can-access-message-thread.service';
|
import { CanAccessMessageThreadService } from 'src/modules/messaging/common/query-hooks/message/can-access-message-thread.service';
|
||||||
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
import { MessageChannelMessageAssociationRepository } from 'src/modules/messaging/common/repositories/message-channel-message-association.repository';
|
||||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook(`message.findOne`)
|
||||||
export class MessageFindOnePreQueryHook implements WorkspacePreQueryHook {
|
export class MessageFindOnePreQueryHook implements WorkspaceQueryHookInstance {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectObjectMetadataRepository(
|
@InjectObjectMetadataRepository(
|
||||||
MessageChannelMessageAssociationWorkspaceEntity,
|
MessageChannelMessageAssociationWorkspaceEntity,
|
||||||
|
|||||||
@ -20,14 +20,8 @@ import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/stan
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CanAccessMessageThreadService,
|
CanAccessMessageThreadService,
|
||||||
{
|
MessageFindOnePreQueryHook,
|
||||||
provide: MessageFindOnePreQueryHook.name,
|
MessageFindManyPreQueryHook,
|
||||||
useClass: MessageFindOnePreQueryHook,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: MessageFindManyPreQueryHook.name,
|
|
||||||
useClass: MessageFindManyPreQueryHook,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class MessagingQueryHookModule {}
|
export class MessagingQueryHookModule {}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { Injectable, MethodNotAllowedException } from '@nestjs/common';
|
import { MethodNotAllowedException } from '@nestjs/common';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
@Injectable()
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
|
|
||||||
|
@WorkspaceQueryHook(`workspaceMember.deleteMany`)
|
||||||
export class WorkspaceMemberDeleteManyPreQueryHook
|
export class WorkspaceMemberDeleteManyPreQueryHook
|
||||||
implements WorkspacePreQueryHook
|
implements WorkspaceQueryHookInstance
|
||||||
{
|
{
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||||
|
|
||||||
import { WorkspacePreQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface';
|
|
||||||
import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||||
|
|
||||||
|
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||||
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
|
||||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity';
|
import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity';
|
||||||
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
|
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
|
||||||
|
|
||||||
@Injectable()
|
@WorkspaceQueryHook(`workspaceMember.deleteOne`)
|
||||||
export class WorkspaceMemberDeleteOnePreQueryHook
|
export class WorkspaceMemberDeleteOnePreQueryHook
|
||||||
implements WorkspacePreQueryHook
|
implements WorkspaceQueryHookInstance
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@InjectWorkspaceRepository(AttachmentWorkspaceEntity)
|
@InjectWorkspaceRepository(AttachmentWorkspaceEntity)
|
||||||
|
|||||||
@ -14,14 +14,8 @@ import { WorkspaceMemberDeleteOnePreQueryHook } from 'src/modules/workspace-memb
|
|||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
WorkspaceMemberDeleteOnePreQueryHook,
|
||||||
provide: WorkspaceMemberDeleteOnePreQueryHook.name,
|
WorkspaceMemberDeleteManyPreQueryHook,
|
||||||
useClass: WorkspaceMemberDeleteOnePreQueryHook,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: WorkspaceMemberDeleteManyPreQueryHook.name,
|
|
||||||
useClass: WorkspaceMemberDeleteManyPreQueryHook,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class WorkspaceMemberQueryHookModule {}
|
export class WorkspaceMemberQueryHookModule {}
|
||||||
|
|||||||
Reference in New Issue
Block a user