Skip to content

Commit

Permalink
wip(api-headless-cms-tasks): caching of list models being deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
brunozoric committed Dec 20, 2024
1 parent f6b4427 commit cee40b4
Show file tree
Hide file tree
Showing 18 changed files with 711 additions and 63 deletions.
90 changes: 90 additions & 0 deletions packages/api-headless-cms-tasks/__tests__/context/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { SecurityIdentity } from "@webiny/api-security/types";
import { ContextPlugin } from "@webiny/api";
import { HcmsTasksContext } from "~/types";

export interface PermissionsArg {
name: string;
locales?: string[];
rwd?: string;
pw?: string;
own?: boolean;
}

export const identity = {
id: "id-12345678",
displayName: "John Doe",
type: "admin"
};

const getSecurityIdentity = () => {
return identity;
};

export const createPermissions = (permissions?: PermissionsArg[]): PermissionsArg[] => {
if (permissions) {
return permissions;
}
return [
{
name: "cms.settings"
},
{
name: "cms.contentModel",
rwd: "rwd"
},
{
name: "cms.contentModelGroup",
rwd: "rwd"
},
{
name: "cms.contentEntry",
rwd: "rwd",
pw: "rcpu"
},
{
name: "cms.endpoint.read"
},
{
name: "cms.endpoint.manage"
},
{
name: "cms.endpoint.preview"
},
{
name: "content.i18n",
locales: ["en-US", "de-DE"]
}
];
};

export const createIdentity = (identity?: SecurityIdentity) => {
if (!identity) {
return getSecurityIdentity();
}
return identity;
};

export const createDummyLocales = () => {
return new ContextPlugin<HcmsTasksContext>(async context => {
const { i18n, security } = context;

await security.authenticate("");

await security.withoutAuthorization(async () => {
const [items] = await i18n.locales.listLocales({
where: {}
});
if (items.length > 0) {
return;
}
await i18n.locales.createLocale({
code: "en-US",
default: true
});
await i18n.locales.createLocale({
code: "de-DE",
default: true
});
});
});
};
111 changes: 111 additions & 0 deletions packages/api-headless-cms-tasks/__tests__/context/plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import apiKeyAuthentication from "@webiny/api-security/plugins/apiKeyAuthentication";
import apiKeyAuthorization from "@webiny/api-security/plugins/apiKeyAuthorization";
import i18nContext from "@webiny/api-i18n/graphql/context";
import graphQLHandlerPlugins from "@webiny/handler-graphql";
import { createHeadlessCmsContext, createHeadlessCmsGraphQL } from "@webiny/api-headless-cms";
import { createWcpContext } from "@webiny/api-wcp";
import { createTenancyAndSecurity } from "./tenancySecurity";
import { createDummyLocales, createPermissions, PermissionsArg } from "./helpers";
import { ApiKey, SecurityIdentity } from "@webiny/api-security/types";
import { ContextPlugin } from "@webiny/api";
import { HcmsTasksContext } from "~/types";
import { mockLocalesPlugins } from "@webiny/api-i18n/graphql/testing";
import { Plugin, PluginCollection } from "@webiny/plugins/types";
import { getStorageOps } from "@webiny/project-utils/testing/environment";
import { createBackgroundTaskContext } from "@webiny/tasks";
import { HeadlessCmsStorageOperations } from "@webiny/api-headless-cms/types";
import { createHcmsTasks } from "~/index";
import { createMockTaskServicePlugin } from "@webiny/project-utils/testing/tasks/mockTaskTriggerTransportPlugin";

export interface CreateHandlerCoreParams {
setupTenancyAndSecurityGraphQL?: boolean;
permissions?: PermissionsArg[];
identity?: SecurityIdentity;
topPlugins?: Plugin | Plugin[] | Plugin[][] | PluginCollection;
plugins?: Plugin | Plugin[] | Plugin[][] | PluginCollection;
bottomPlugins?: Plugin | Plugin[] | Plugin[][] | PluginCollection;
path?: `manage/${string}-${string}}` | `read/${string}-${string}}` | string;
}

process.env.S3_BUCKET = "my-mock-s3-bucket";

export const createHandlerCore = (params: CreateHandlerCoreParams = {}) => {
const tenant = {
id: "root",
name: "Root",
parent: null
};
const locale = "en-US";
const {
permissions,
identity,
plugins = [],
topPlugins = [],
bottomPlugins = [],
setupTenancyAndSecurityGraphQL
} = params;

const cmsStorage = getStorageOps<HeadlessCmsStorageOperations>("cms");
const i18nStorage = getStorageOps<any[]>("i18n");

return {
storageOperations: cmsStorage.storageOperations,
tenant,
locale,
plugins: [
topPlugins,
createWcpContext(),
...cmsStorage.plugins,
...createTenancyAndSecurity({
setupGraphQL: setupTenancyAndSecurityGraphQL,
permissions: createPermissions(permissions),
identity
}),
{
type: "context",
name: "context-security-tenant",
async apply(context) {
context.security.getApiKeyByToken = async (
token: string
): Promise<ApiKey | null> => {
if (!token || token !== "aToken") {
return null;
}
const apiKey = "a1234567890";
return {
id: apiKey,
name: apiKey,
tenant: tenant.id,
permissions: identity?.permissions || [],
token,
createdBy: {
id: "test",
displayName: "test",
type: "admin"
},
description: "test",
createdOn: new Date().toISOString(),
webinyVersion: context.WEBINY_VERSION
};
};
}
} as ContextPlugin<HcmsTasksContext>,
apiKeyAuthentication({ identityType: "api-key" }),
apiKeyAuthorization({ identityType: "api-key" }),
i18nContext(),
i18nStorage.storageOperations,
createDummyLocales(),
mockLocalesPlugins(),
createHeadlessCmsContext({
storageOperations: cmsStorage.storageOperations
}),
createBackgroundTaskContext(),
createHeadlessCmsGraphQL(),
plugins,
graphQLHandlerPlugins(),
createHcmsTasks(),
createMockTaskServicePlugin(),
bottomPlugins
]
};
};
102 changes: 102 additions & 0 deletions packages/api-headless-cms-tasks/__tests__/context/tenancySecurity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Plugin } from "@webiny/plugins/Plugin";
import { createTenancyContext, createTenancyGraphQL } from "@webiny/api-tenancy";
import { createSecurityContext, createSecurityGraphQL } from "@webiny/api-security";
import {
SecurityIdentity,
SecurityPermission,
SecurityStorageOperations
} from "@webiny/api-security/types";
import { ContextPlugin } from "@webiny/api";
import { BeforeHandlerPlugin } from "@webiny/handler";
import { HcmsTasksContext } from "~/types";
import { getStorageOps } from "@webiny/project-utils/testing/environment";
import { TenancyStorageOperations, Tenant } from "@webiny/api-tenancy/types";

interface Config {
setupGraphQL?: boolean;
permissions: SecurityPermission[];
identity?: SecurityIdentity | null;
}

export const defaultIdentity: SecurityIdentity = {
id: "id-12345678",
type: "admin",
displayName: "John Doe"
};

export const createTenancyAndSecurity = ({
setupGraphQL,
permissions,
identity
}: Config): Plugin[] => {
const tenancyStorage = getStorageOps<TenancyStorageOperations>("tenancy");
const securityStorage = getStorageOps<SecurityStorageOperations>("security");

return [
createTenancyContext({ storageOperations: tenancyStorage.storageOperations }),
setupGraphQL ? createTenancyGraphQL() : null,
createSecurityContext({ storageOperations: securityStorage.storageOperations }),
setupGraphQL ? createSecurityGraphQL() : null,
new ContextPlugin<HcmsTasksContext>(async context => {
await context.tenancy.createTenant({
id: "root",
name: "Root",
parent: "",
description: "Root tenant",
tags: []
});

await context.tenancy.createTenant({
id: "webiny",
name: "Webiny",
parent: "",
description: "Webiny tenant",
tags: []
});

await context.tenancy.createTenant({
id: "dev",
name: "Dev",
parent: "",
description: "Dev tenant",
tags: []
});

await context.tenancy.createTenant({
id: "sales",
name: "Sales",
parent: "",
description: "Sales tenant",
tags: []
});
}),
new ContextPlugin<HcmsTasksContext>(async context => {
context.tenancy.setCurrentTenant({
id: "root",
name: "Root",
webinyVersion: context.WEBINY_VERSION
} as unknown as Tenant);

context.security.addAuthenticator(async () => {
return identity || defaultIdentity;
});

context.security.addAuthorizer(async () => {
const { headers = {} } = context.request || {};
if (headers["authorization"]) {
return null;
}

return permissions || [{ name: "*" }];
});
}),
new BeforeHandlerPlugin<HcmsTasksContext>(context => {
const { headers = {} } = context.request || {};
if (headers["authorization"]) {
return context.security.authenticate(headers["authorization"]);
}

return context.security.authenticate("");
})
].filter(Boolean) as Plugin[];
};
52 changes: 52 additions & 0 deletions packages/api-headless-cms-tasks/__tests__/context/useHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { createHandlerCore, CreateHandlerCoreParams } from "./plugins";
import { createRawEventHandler, createRawHandler } from "@webiny/handler-aws";
import { HcmsTasksContext } from "~/types";
import { defaultIdentity } from "./tenancySecurity";
import { LambdaContext } from "@webiny/handler-aws/types";
import { getElasticsearchClient } from "@webiny/project-utils/testing/elasticsearch";

interface CmsHandlerEvent {
path: string;
headers: {
["x-tenant"]: string;
[key: string]: string;
};
}

type Params = CreateHandlerCoreParams;
export const useHandler = <C extends HcmsTasksContext = HcmsTasksContext>(params: Params = {}) => {
const core = createHandlerCore(params);

const plugins = [...core.plugins].concat([
createRawEventHandler<CmsHandlerEvent, C, C>(async ({ context }) => {
return context;
})
]);

const handler = createRawHandler<CmsHandlerEvent, C>({
plugins,
debug: process.env.DEBUG === "true"
});

const { elasticsearchClient } = getElasticsearchClient({ name: "api-headless-cms-ddb-es" });

return {
plugins,
identity: params.identity || defaultIdentity,
tenant: core.tenant,
locale: core.locale,
elasticsearch: elasticsearchClient,
handler: (input?: CmsHandlerEvent) => {
const payload: CmsHandlerEvent = {
path: "/cms/manage/en-US",
headers: {
"x-webiny-cms-endpoint": "manage",
"x-webiny-cms-locale": "en-US",
"x-tenant": "root"
},
...input
};
return handler(payload, {} as LambdaContext);
}
};
};
Loading

0 comments on commit cee40b4

Please sign in to comment.