-
Notifications
You must be signed in to change notification settings - Fork 617
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip(api-headless-cms-tasks): caching of list models being deleted
- Loading branch information
1 parent
f6b4427
commit cee40b4
Showing
18 changed files
with
711 additions
and
63 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
packages/api-headless-cms-tasks/__tests__/context/helpers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
111
packages/api-headless-cms-tasks/__tests__/context/plugins.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
102
packages/api-headless-cms-tasks/__tests__/context/tenancySecurity.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
52
packages/api-headless-cms-tasks/__tests__/context/useHandler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
}; | ||
}; |
Oops, something went wrong.