diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap index 36f39965a9b..3b9aa6928f1 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap @@ -18,6 +18,7 @@ Object { }, Object { "apiKeyConfig": Object { + "apiKeyExpirationDate": undefined, "apiKeyExpirationDays": undefined, "description": undefined, }, diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts index 28e2aec71d3..e8dfa51770a 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts @@ -30,7 +30,7 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', jest.mock('amplify-cli-core'); -const fs_mock = (fs as unknown) as jest.Mocked; +const fs_mock = fs as unknown as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts new file mode 100644 index 00000000000..871b8c8f1ea --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts @@ -0,0 +1,44 @@ +import { $TSContext } from 'amplify-cli-core'; +import * as prompts from 'amplify-prompts'; +import { promptToAddApiKey } from '../../../provider-utils/awscloudformation/prompt-to-add-api-key'; +import * as walkthrough from '../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; +import * as cfnApiArtifactHandler from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; + +jest.mock('../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough', () => ({ + askApiKeyQuestions: jest.fn(), +})); + +jest.mock('../../../provider-utils/awscloudformation/cfn-api-artifact-handler', () => ({ + getCfnApiArtifactHandler: jest.fn(() => { + return { updateArtifacts: jest.fn() }; + }), +})); + +jest.mock('amplify-prompts', () => ({ + prompter: { + confirmContinue: jest.fn().mockImplementation(() => true), + }, +})); + +describe('prompt to add Api Key', () => { + it('runs through expected user flow: print info, update files', async () => { + const envName = 'envone'; + const ctx = { + amplify: { + getEnvInfo() { + return { envName }; + }, + }, + } as unknown as $TSContext; + + jest.spyOn(prompts.prompter, 'confirmContinue'); + jest.spyOn(walkthrough, 'askApiKeyQuestions'); + jest.spyOn(cfnApiArtifactHandler, 'getCfnApiArtifactHandler'); + + await promptToAddApiKey(ctx); + + expect(prompts.prompter.confirmContinue).toHaveBeenCalledWith('Would you like to create an API Key?'); + expect(walkthrough.askApiKeyQuestions).toHaveBeenCalledTimes(1); + expect(cfnApiArtifactHandler.getCfnApiArtifactHandler).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts index a664b0b4698..1d7ed55cdfd 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts @@ -3,7 +3,7 @@ import { askAdditionalAuthQuestions, } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { FeatureFlags, CLIEnvironmentProvider, FeatureFlagRegistration } from 'amplify-cli-core'; +import { FeatureFlags } from 'amplify-cli-core'; jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ getAppSyncAuthConfig: jest.fn(), authConfigHasApiKey: jest.fn(), diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap index 73049e4ca95..3c18c0fa241 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts.snap @@ -12,6 +12,7 @@ Object { exports[`AppSyncAuthType to authConfig maps API_KEY correctly 1`] = ` Object { "apiKeyConfig": Object { + "apiKeyExpirationDate": undefined, "apiKeyExpirationDays": 120, "description": undefined, }, @@ -47,6 +48,7 @@ Object { exports[`authConfig to AppSyncAuthType maps API_KEY auth correctly 1`] = ` Object { + "apiKeyExpirationDate": undefined, "expirationTime": 120, "keyDescription": "api key description", "mode": "API_KEY", diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts new file mode 100644 index 00000000000..a895da7f667 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts @@ -0,0 +1,21 @@ +import { defineGlobalSandboxMode } from '../../../../provider-utils/awscloudformation/utils/global-sandbox-mode'; +import { $TSContext } from 'amplify-cli-core'; + +describe('global sandbox mode GraphQL directive', () => { + it('returns AMPLIFY_DIRECTIVE type with code comment, directive, and env name', () => { + const envName = 'envone'; + const ctx = <$TSContext>{ + amplify: { + getEnvInfo() { + return { envName }; + }, + }, + }; + + expect(defineGlobalSandboxMode(ctx)) + .toBe(`# This allows public create, read, update, and delete access for a limited time to all models via API Key. +# To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth +type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: \"${envName}\") # FOR TESTING ONLY!\n +`); + }); +}); diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index ba4fd2d3c06..17b1f7b93d9 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -17,6 +17,7 @@ export { processDockerConfig, } from './provider-utils/awscloudformation/utils/containers-artifacts'; export { getContainers } from './provider-utils/awscloudformation/docker-compose'; +export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; const category = 'api'; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts index cc421715b5d..ecf2dddbd55 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts @@ -1,4 +1,4 @@ -import { isResourceNameUnique } from 'amplify-cli-core'; +import { isResourceNameUnique, FeatureFlags } from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts new file mode 100644 index 00000000000..5184b0d3dbb --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts @@ -0,0 +1,20 @@ +import { $TSContext } from 'amplify-cli-core'; +import { askApiKeyQuestions } from './service-walkthroughs/appSync-walkthrough'; +import { authConfigToAppSyncAuthType } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; +import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; +import { prompter } from 'amplify-prompts'; + +export async function promptToAddApiKey(context: $TSContext): Promise { + if (await prompter.confirmContinue('Would you like to create an API Key?')) { + const apiKeyConfig = await askApiKeyQuestions(); + const authConfig = [apiKeyConfig]; + + await getCfnApiArtifactHandler(context).updateArtifacts({ + version: 1, + serviceModification: { + serviceName: 'AppSync', + additionalAuthTypes: authConfig.map(authConfigToAppSyncAuthType), + }, + }); + } +} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index 8c29175f156..c8561d30e01 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts @@ -22,6 +22,8 @@ import { $TSContext, open, } from 'amplify-cli-core'; +import { Duration, Expiration } from '@aws-cdk/core'; +import { defineGlobalSandboxMode } from '../utils/global-sandbox-mode'; const serviceName = 'AppSync'; const elasticContainerServiceName = 'ElasticContainer'; @@ -215,7 +217,7 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile authConfig = { defaultAuthentication: { apiKeyConfig: { - apiKeyExpirationDays: 7 + apiKeyExpirationDays: 7, }, authenticationType: 'API_KEY', }, @@ -226,21 +228,22 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile // Repeat prompt until user selects Continue // while (!continuePrompt) { - const getAuthModeChoice = async () => { if (authConfig.defaultAuthentication.authenticationType === 'API_KEY') { - return `${authProviderChoices.find(choice => choice.value === authConfig.defaultAuthentication.authenticationType).name} (default, expiration time: ${authConfig.defaultAuthentication.apiKeyConfig.apiKeyExpirationDays} days from now)`; + return `${ + authProviderChoices.find(choice => choice.value === authConfig.defaultAuthentication.authenticationType).name + } (default, expiration time: ${authConfig.defaultAuthentication.apiKeyConfig.apiKeyExpirationDays} days from now)`; } return `${authProviderChoices.find(choice => choice.value === authConfig.defaultAuthentication.authenticationType).name} (default)`; }; const getAdditionalAuthModeChoices = async () => { let additionalAuthModesText = ''; - authConfig.additionalAuthenticationProviders.map(async (authMode) => { - additionalAuthModesText += `, ${authProviderChoices.find(choice => choice.value === authMode.authenticationType).name}` + authConfig.additionalAuthenticationProviders.map(async authMode => { + additionalAuthModesText += `, ${authProviderChoices.find(choice => choice.value === authMode.authenticationType).name}`; }); return additionalAuthModesText; - } + }; const basicInfoQuestionChoices = []; @@ -261,7 +264,9 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile if (resolverConfig?.project) { basicInfoQuestionChoices.push({ - name: chalk`{bold Conflict resolution strategy:} ${conflictResolutionHanlderChoices.find(x => x.value === resolverConfig.project.ConflictHandler).name}`, + name: chalk`{bold Conflict resolution strategy:} ${ + conflictResolutionHanlderChoices.find(x => x.value === resolverConfig.project.ConflictHandler).name + }`, value: 'CONFLICT_STRATEGY', }); } @@ -281,7 +286,7 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile let { basicApiSettings } = await inquirer.prompt([basicInfoQuestion]); - switch(basicApiSettings) { + switch (basicApiSettings) { case 'API_NAME': const resourceQuestions = [ { @@ -323,7 +328,6 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile }, resolverConfig, }; - }; const updateApiInputWalkthrough = async (context, project, resolverConfig, modelTypes) => { @@ -380,6 +384,7 @@ const updateApiInputWalkthrough = async (context, project, resolverConfig, model export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); + const useExperimentalPipelineTransformer = FeatureFlags.getBoolean('graphQLTransformer.useExperimentalPipelinedTransformer'); if (resourceName) { const errMessage = @@ -397,7 +402,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen let askToEdit = true; // Schema template selection - const schemaTemplateOptions = FeatureFlags.getBoolean('graphQLTransformer.useExperimentalPipelinedTransformer') ? schemaTemplatesV2 : schemaTemplatesV1; + const schemaTemplateOptions = useExperimentalPipelineTransformer ? schemaTemplatesV2 : schemaTemplatesV1; const templateSelectionQuestion = { type: inputs[4].type, name: inputs[4].key, @@ -408,7 +413,8 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent = fs.readFileSync(schemaFilePath, 'utf8'); + schemaContent += useExperimentalPipelineTransformer ? defineGlobalSandboxMode(context) : ''; + schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); return { ...basicInfoAnswers, @@ -481,8 +487,10 @@ export const updateWalkthrough = async (context): Promise => { async function displayApiInformation(context, resource, project) { let authModes: string[] = []; - authModes.push(`- Default: ${await displayAuthMode(context, resource, resource.output.authConfig.defaultAuthentication.authenticationType)}`); - await resource.output.authConfig.additionalAuthenticationProviders.map(async (authMode) => { + authModes.push( + `- Default: ${await displayAuthMode(context, resource, resource.output.authConfig.defaultAuthentication.authenticationType)}`, + ); + await resource.output.authConfig.additionalAuthenticationProviders.map(async authMode => { authModes.push(`- ${await displayAuthMode(context, resource, authMode.authenticationType)}`); }); @@ -501,7 +509,11 @@ async function displayApiInformation(context, resource, project) { context.print.success('Conflict detection (required for DataStore)'); if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - context.print.info(`- Conflict resolution strategy: ${conflictResolutionHanlderChoices.find(choice => choice.value === project.config.ResolverConfig.project.ConflictHandler).name}`); + context.print.info( + `- Conflict resolution strategy: ${ + conflictResolutionHanlderChoices.find(choice => choice.value === project.config.ResolverConfig.project.ConflictHandler).name + }`, + ); } else { context.print.info('- Disabled'); } @@ -519,7 +531,9 @@ async function displayAuthMode(context, resource, authMode) { return authProviderChoices.find(choice => choice.value === authMode).name; } let apiKeyExpiresDate = new Date(apiKeyExpires * 1000); - return `${authProviderChoices.find(choice => choice.value === authMode).name} expiring ${apiKeyExpiresDate}: ${resource.output.GraphQLAPIKeyOutput}`; + return `${authProviderChoices.find(choice => choice.value === authMode).name} expiring ${apiKeyExpiresDate}: ${ + resource.output.GraphQLAPIKeyOutput + }`; } return authProviderChoices.find(choice => choice.value === authMode).name; } @@ -668,9 +682,11 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut if (await context.prompt.confirm('Configure additional auth types?')) { // Get additional auth configured const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== defaultAuthType); - const currentAdditionalAuth = ((currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders - ? currentAuthConfig.additionalAuthenticationProviders - : []) as any[]).map(authProvider => authProvider.authenticationType); + const currentAdditionalAuth = ( + (currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders + ? currentAuthConfig.additionalAuthenticationProviders + : []) as any[] + ).map(authProvider => authProvider.authenticationType); const additionalProvidersQuestion: CheckboxQuestion = { type: 'checkbox', @@ -685,7 +701,12 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut for (let i = 0; i < additionalProvidersAnswer.authType.length; i += 1) { const authProvider = additionalProvidersAnswer.authType[i]; - const config = await askAuthQuestions(authProvider, context, true, currentAuthConfig?.additionalAuthenticationProviders?.find(authSetting => authSetting.authenticationType == authProvider)); + const config = await askAuthQuestions( + authProvider, + context, + true, + currentAuthConfig?.additionalAuthenticationProviders?.find(authSetting => authSetting.authenticationType == authProvider), + ); authConfig.additionalAuthenticationProviders.push(config); } @@ -759,7 +780,7 @@ async function askUserPoolQuestions(context) { }; } -async function askApiKeyQuestions(authSettings) { +export async function askApiKeyQuestions(authSettings = undefined) { let defaultValues = { apiKeyExpirationDays: 7, description: undefined, @@ -785,6 +806,8 @@ async function askApiKeyQuestions(authSettings) { ]; const apiKeyConfig = await inquirer.prompt(apiKeyQuestions); + const apiKeyExpirationDaysNum = Number(apiKeyConfig.apiKeyExpirationDays); + apiKeyConfig.apiKeyExpirationDate = Expiration.after(Duration.days(apiKeyExpirationDaysNum)).date; return { authenticationType: 'API_KEY', @@ -857,9 +880,10 @@ function validateDays(input) { } function validateIssuerUrl(input) { - const isValid = /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test( - input, - ); + const isValid = + /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test( + input, + ); if (!isValid) { return 'The value must be a valid URI with a trailing forward slash. HTTPS must be used instead of HTTP unless you are using localhost.'; @@ -959,8 +983,8 @@ const buildPolicyResource = (resourceName: string, path: string | null) => { { Ref: `${category}${resourceName}GraphQLAPIIdOutput`, }, - ...(path ? [path] : []) - ] + ...(path ? [path] : []), + ], ], }; }; @@ -968,7 +992,8 @@ const buildPolicyResource = (resourceName: string, path: string | null) => { const templateSchemaFilter = authConfig => { const authIncludesCognito = getAuthTypes(authConfig).includes('AMAZON_COGNITO_USER_POOLS'); return (templateOption: ListChoiceOptions): boolean => - authIncludesCognito || templateOption.name !== 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)'; + authIncludesCognito || + templateOption.name !== 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)'; }; const getAuthTypes = authConfig => { diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts index d52094eae50..c1a8dde916a 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts @@ -30,6 +30,7 @@ const authConfigToAppSyncAuthTypeMap: Record AppSyn API_KEY: authConfig => ({ mode: 'API_KEY', expirationTime: authConfig.apiKeyConfig.apiKeyExpirationDays, + apiKeyExpirationDate: authConfig.apiKeyConfig?.apiKeyExpirationDate, keyDescription: authConfig.apiKeyConfig.description, }), AWS_IAM: () => ({ @@ -54,6 +55,7 @@ const appSyncAuthTypeToAuthConfigMap: Record $TSAny; sharedQuestions: () => $TSAny; showAllHelp: () => $TSAny; + showGlobalSandboxModeWarning: (context: $TSContext) => $TSAny; showHelp: (header: string, commands: { name: string; description: string }[]) => $TSAny; showHelpfulProviderLinks: (context: $TSContext) => $TSAny; showResourceTable: () => $TSAny; diff --git a/packages/amplify-cli/src/__tests__/commands/status.test.ts b/packages/amplify-cli/src/__tests__/commands/status.test.ts index d22a798a354..30f9dc59605 100644 --- a/packages/amplify-cli/src/__tests__/commands/status.test.ts +++ b/packages/amplify-cli/src/__tests__/commands/status.test.ts @@ -1,5 +1,3 @@ -import { UnknownArgumentError } from 'amplify-cli-core'; - describe('amplify status: ', () => { const { run } = require('../../commands/status'); const runStatusCmd = run; @@ -11,17 +9,10 @@ describe('amplify status: ', () => { }); it('status run method should call context.amplify.showStatusTable', async () => { - const cliInput = { - command: 'status', - subCommands: [], - options: { - verbose: true, - }, - }; - const mockContextNoCLArgs = { amplify: { showStatusTable: jest.fn(), + showGlobalSandboxModeWarning: jest.fn(), showHelpfulProviderLinks: jest.fn(), getCategoryPluginInfo: jest.fn().mockReturnValue({ packageLocation: mockPath }), }, @@ -43,6 +34,7 @@ describe('amplify status: ', () => { const mockContextWithVerboseOptionAndCLArgs = { amplify: { showStatusTable: jest.fn(), + showGlobalSandboxModeWarning: jest.fn(), showHelpfulProviderLinks: jest.fn(), getCategoryPluginInfo: jest.fn().mockReturnValue({ packageLocation: statusPluginInfo }), }, @@ -61,6 +53,7 @@ describe('amplify status: ', () => { const mockContextWithVerboseOptionWithCategoriesAndCLArgs = { amplify: { showStatusTable: jest.fn(), + showGlobalSandboxModeWarning: jest.fn(), showHelpfulProviderLinks: jest.fn(), getCategoryPluginInfo: jest.fn().mockReturnValue({ packageLocation: statusPluginInfo }), }, @@ -82,6 +75,7 @@ describe('amplify status: ', () => { const mockContextWithHelpSubcommandAndCLArgs = { amplify: { showStatusTable: jest.fn(), + showGlobalSandboxModeWarning: jest.fn(), showHelpfulProviderLinks: jest.fn(), getCategoryPluginInfo: jest.fn().mockReturnValue({ packageLocation: statusPluginInfo }), }, @@ -94,5 +88,4 @@ describe('amplify status: ', () => { //TBD: to move ViewResourceTableParams into a separate file for mocking instance functions. expect(mockContextWithHelpSubcommandAndCLArgs.amplify.showStatusTable.mock.calls.length).toBe(0); }); - }); diff --git a/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/get-api-key-config.test.ts b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/get-api-key-config.test.ts new file mode 100644 index 00000000000..26b38ec1f54 --- /dev/null +++ b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/get-api-key-config.test.ts @@ -0,0 +1,100 @@ +import fs from 'fs'; +import { getAppSyncApiConfig, getApiKeyConfig, apiKeyIsActive, hasApiKey } from '../../../extensions/amplify-helpers/get-api-key-config'; + +let amplifyMeta; + +jest.mock('amplify-cli-core', () => { + const original = jest.requireActual('amplify-cli-core'); + return { + ...original, + stateManager: { + metaFileExists: jest.fn(), + getMeta: jest.fn().mockImplementation(() => JSON.parse(amplifyMeta.toString())), + }, + }; +}); + +describe('getAppSyncApiConfig', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`); + }); + + it('returns the api object', async () => { + const result = getAppSyncApiConfig(); + + expect(result).toStrictEqual({ + service: 'AppSync', + providerPlugin: 'awscloudformation', + output: { + authConfig: { + defaultAuthentication: { + authenticationType: 'AWS_IAM', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'API_KEY', + apiKeyConfig: { + apiKeyExpirationDays: 2, + apiKeyExpirationDate: '2021-08-20T20:38:07.585Z', + description: '', + }, + }, + ], + }, + globalSandboxModeConfig: { + env: 'dev', + }, + }, + }); + }); +}); + +describe('getApiKeyConfig', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`); + }); + + it('returns the api key config', () => { + const result = getApiKeyConfig(); + + expect(result).toStrictEqual({ + apiKeyExpirationDays: 2, + apiKeyExpirationDate: '2021-08-20T20:38:07.585Z', + description: '', + }); + }); +}); + +describe('apiKeyIsActive', () => { + describe('with expired key', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`); + }); + + it('returns false', () => { + expect(apiKeyIsActive()).toBe(false); + }); + }); + + describe('with no api key config', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta-3.json`); + }); + + it('returns false', () => { + expect(apiKeyIsActive()).toBe(false); + }); + }); +}); + +describe('hasApiKey', () => { + describe('if api key config is present', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`); + }); + + it('returns true if api key is present', () => { + expect(hasApiKey()).toBe(true); + }); + }); +}); diff --git a/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/show-global-sandbox-mode-warning.test.ts b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/show-global-sandbox-mode-warning.test.ts new file mode 100644 index 00000000000..2938d65216e --- /dev/null +++ b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/show-global-sandbox-mode-warning.test.ts @@ -0,0 +1,105 @@ +import { + globalSandboxModeEnabled, + showGlobalSandboxModeWarning, +} from '../../../extensions/amplify-helpers/show-global-sandbox-mode-warning'; +import { $TSContext } from '../../../../../amplify-cli-core/lib'; +import fs from 'fs'; +import chalk from 'chalk'; + +let ctx, amplifyMeta; + +jest.mock('amplify-cli-core', () => ({ + stateManager: { + getMeta: jest.fn(() => JSON.parse(amplifyMeta.toString())), + }, +})); + +describe('global sandbox mode warning', () => { + beforeEach(() => { + const envName = 'dev'; + ctx = { + amplify: { + getEnvInfo() { + return { envName }; + }, + }, + print: { + info() { + // noop + }, + }, + } as unknown as $TSContext; + }); + + describe('globalSandboxModeEnabled', () => { + describe('enabled', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`); + }); + + it('returns true', async () => { + expect(globalSandboxModeEnabled(ctx)).toBe(true); + }); + }); + + describe('not specified', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta-2.json`); + }); + + it('returns false', async () => { + expect(globalSandboxModeEnabled(ctx)).toBe(false); + }); + }); + }); + + describe('showGlobalSandboxModeWarning', () => { + describe('sandbox mode enabled', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`); + }); + + it('prints warning message', async () => { + jest.spyOn(ctx.print, 'info'); + + await showGlobalSandboxModeWarning(ctx); + + expect(ctx.print.info).toBeCalledWith(` +${chalk.yellow(`⚠️ WARNING: ${chalk.green('"type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key"')} in your GraphQL schema +allows public create, read, update, and delete access to all models via API Key. This +should only be used for testing purposes. API Key expiration date is: 8/20/2021 + +To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth`)} +`); + }); + }); + + describe('sandbox mode not specified', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta-2.json`); + }); + + it('does not print warning', async () => { + jest.spyOn(ctx.print, 'info'); + + await showGlobalSandboxModeWarning(ctx); + + expect(ctx.print.info).toBeCalledTimes(0); + }); + }); + + describe('no api key config', () => { + beforeAll(() => { + amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta-3.json`); + }); + + it('does not print warning', async () => { + jest.spyOn(ctx.print, 'info'); + + await showGlobalSandboxModeWarning(ctx); + + expect(ctx.print.info).toBeCalledTimes(0); + }); + }); + }); +}); diff --git a/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta-2.json b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta-2.json new file mode 100644 index 00000000000..9bd3f8293be --- /dev/null +++ b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta-2.json @@ -0,0 +1,25 @@ +{ + "api": { + "ampapp": { + "service": "AppSync", + "providerPlugin": "awscloudformation", + "output": { + "authConfig": { + "defaultAuthentication": { + "authenticationType": "AWS_IAM" + }, + "additionalAuthenticationProviders": [ + { + "authenticationType": "API_KEY", + "apiKeyConfig": { + "apiKeyExpirationDays": 2, + "apiKeyExpirationDate": "2021-08-20T20:38:07.585Z", + "description": "" + } + } + ] + } + } + } + } +} diff --git a/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta-3.json b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta-3.json new file mode 100644 index 00000000000..7aa92695860 --- /dev/null +++ b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta-3.json @@ -0,0 +1,16 @@ +{ + "api": { + "ampapp": { + "service": "AppSync", + "providerPlugin": "awscloudformation", + "output": { + "authConfig": { + "defaultAuthentication": { + "authenticationType": "AWS_IAM" + }, + "additionalAuthenticationProviders": [] + } + } + } + } +} diff --git a/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta.json b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta.json new file mode 100644 index 00000000000..cb9a35d4025 --- /dev/null +++ b/packages/amplify-cli/src/__tests__/extensions/amplify-helpers/testData/mockLocalCloud/amplify-meta.json @@ -0,0 +1,28 @@ +{ + "api": { + "ampapp": { + "service": "AppSync", + "providerPlugin": "awscloudformation", + "output": { + "authConfig": { + "defaultAuthentication": { + "authenticationType": "AWS_IAM" + }, + "additionalAuthenticationProviders": [ + { + "authenticationType": "API_KEY", + "apiKeyConfig": { + "apiKeyExpirationDays": 2, + "apiKeyExpirationDate": "2021-08-20T20:38:07.585Z", + "description": "" + } + } + ] + }, + "globalSandboxModeConfig": { + "env": "dev" + } + } + } + } +} diff --git a/packages/amplify-cli/src/commands/status.ts b/packages/amplify-cli/src/commands/status.ts index 3e11576346a..c821f9c1c94 100644 --- a/packages/amplify-cli/src/commands/status.ts +++ b/packages/amplify-cli/src/commands/status.ts @@ -1,26 +1,28 @@ -import { ViewResourceTableParams, CLIParams, $TSContext } from "amplify-cli-core"; +import { ViewResourceTableParams, CLIParams, $TSContext } from 'amplify-cli-core'; +export const run = async (context: $TSContext) => { + const cliParams: CLIParams = { + cliCommand: context?.input?.command, + cliSubcommands: context?.input?.subCommands, + cliOptions: context?.input?.options, + }; -export const run = async (context : $TSContext) => { - const cliParams:CLIParams = { cliCommand : context?.input?.command, - cliSubcommands: context?.input?.subCommands, - cliOptions : context?.input?.options } - - const view = new ViewResourceTableParams( cliParams ); - if ( context?.input?.subCommands?.includes("help")){ - context.print.info( view.getStyledHelp() ); + const view = new ViewResourceTableParams(cliParams); + if (context?.input?.subCommands?.includes('help')) { + context.print.info(view.getStyledHelp()); } else { try { - await context.amplify.showStatusTable( view ); + await context.amplify.showStatusTable(view); + await context.amplify.showGlobalSandboxModeWarning(context); await context.amplify.showHelpfulProviderLinks(context); await showAmplifyConsoleHostingStatus(context); - } catch ( e ){ + } catch (e) { view.logErrorException(e, context); } } }; -async function showAmplifyConsoleHostingStatus( context) { +async function showAmplifyConsoleHostingStatus(context) { const pluginInfo = context.amplify.getCategoryPluginInfo(context, 'hosting', 'amplifyhosting'); if (pluginInfo && pluginInfo.packageLocation) { const { status } = await import(pluginInfo.packageLocation); diff --git a/packages/amplify-cli/src/domain/amplify-toolkit.ts b/packages/amplify-cli/src/domain/amplify-toolkit.ts index 55f1b41b753..512d7fefd9c 100644 --- a/packages/amplify-cli/src/domain/amplify-toolkit.ts +++ b/packages/amplify-cli/src/domain/amplify-toolkit.ts @@ -38,6 +38,7 @@ export class AmplifyToolkit { private _removeResource: any; private _sharedQuestions: any; private _showAllHelp: any; + private _showGlobalSandboxModeWarning: any; private _showHelp: any; private _showHelpfulProviderLinks: any; private _showResourceTable: any; @@ -240,6 +241,12 @@ export class AmplifyToolkit { this._sharedQuestions = this._sharedQuestions || require(path.join(this._amplifyHelpersDirPath, 'shared-questions')).sharedQuestions; return this._sharedQuestions; } + get showGlobalSandboxModeWarning(): any { + this._showGlobalSandboxModeWarning = + this._showGlobalSandboxModeWarning || + require(path.join(this._amplifyHelpersDirPath, 'show-global-sandbox-mode-warning')).showGlobalSandboxModeWarning; + return this._showGlobalSandboxModeWarning; + } get showHelp(): any { this._showHelp = this._showHelp || require(path.join(this._amplifyHelpersDirPath, 'show-help')).showHelp; return this._showHelp; @@ -261,8 +268,7 @@ export class AmplifyToolkit { } get showStatusTable(): any { - this._showStatusTable = - this._showStatusTable || require(path.join(this._amplifyHelpersDirPath, 'resource-status')).showStatusTable; + this._showStatusTable = this._showStatusTable || require(path.join(this._amplifyHelpersDirPath, 'resource-status')).showStatusTable; return this._showStatusTable; } diff --git a/packages/amplify-cli/src/extensions/amplify-helpers/get-api-key-config.ts b/packages/amplify-cli/src/extensions/amplify-helpers/get-api-key-config.ts new file mode 100644 index 00000000000..2fbdccad3c9 --- /dev/null +++ b/packages/amplify-cli/src/extensions/amplify-helpers/get-api-key-config.ts @@ -0,0 +1,51 @@ +import { stateManager } from 'amplify-cli-core'; +import { ApiKeyConfig } from '@aws-amplify/graphql-transformer-interfaces'; + +export function getAppSyncApiConfig(): any { + const apiConfig = stateManager.getMeta()?.api; + let appSyncApi; + + Object.keys(apiConfig).forEach(k => { + if (apiConfig[k]['service'] === 'AppSync') appSyncApi = apiConfig[k]; + }); + + return appSyncApi; +} + +function getDefaultIfApiKey(): ApiKeyConfig | void { + const authConfig = getAppSyncApiConfig()?.output?.authConfig; + const { defaultAuthentication } = authConfig; + + if (defaultAuthentication.authenticationType === 'API_KEY') return defaultAuthentication.apiKeyConfig; +} + +function getAdditionalApiKeyConfig(): ApiKeyConfig | void { + const authConfig = getAppSyncApiConfig()?.output?.authConfig; + const { additionalAuthenticationProviders } = authConfig; + let apiKeyConfig; + + additionalAuthenticationProviders.forEach(authProvider => { + if (authProvider.authenticationType === 'API_KEY') apiKeyConfig = authProvider.apiKeyConfig; + }); + + return apiKeyConfig; +} + +export function getApiKeyConfig(): ApiKeyConfig | void { + return getDefaultIfApiKey() || getAdditionalApiKeyConfig(); +} + +export function apiKeyIsActive(): boolean { + const today = new Date(); + const { apiKeyExpirationDate } = getApiKeyConfig() || {}; + + if (!apiKeyExpirationDate) return false; + + return new Date(apiKeyExpirationDate) > today; +} + +export function hasApiKey(): boolean { + const apiKeyConfig = getApiKeyConfig(); + + return !!apiKeyConfig && !!apiKeyConfig?.apiKeyExpirationDate; +} diff --git a/packages/amplify-cli/src/extensions/amplify-helpers/prompt-sandbox-mode-api-key.ts b/packages/amplify-cli/src/extensions/amplify-helpers/prompt-sandbox-mode-api-key.ts new file mode 100644 index 00000000000..9beb0eda74a --- /dev/null +++ b/packages/amplify-cli/src/extensions/amplify-helpers/prompt-sandbox-mode-api-key.ts @@ -0,0 +1,19 @@ +import chalk from 'chalk'; +import { $TSContext } from 'amplify-cli-core'; +import { promptToAddApiKey } from 'amplify-category-api'; +import { globalSandboxModeEnabled, showGlobalSandboxModeWarning } from './show-global-sandbox-mode-warning'; +import { apiKeyIsActive, hasApiKey } from './get-api-key-config'; + +export async function promptSandboxModeApiKey(context: $TSContext): Promise { + if (globalSandboxModeEnabled(context)) { + if (!apiKeyIsActive() || !hasApiKey()) { + context.print.info(` +⚠️ WARNING: Global Sandbox Mode has been enabled, which requires a valid API key. If +you'd like to disable, remove ${chalk.green('"type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key"')} +from your GraphQL schema and run 'amplify push' again. If you'd like to proceed with +sandbox mode disabled in '${context.amplify.getEnvInfo().envName}', do not create an API Key. +`); + await promptToAddApiKey(context); + } else showGlobalSandboxModeWarning(context); + } +} diff --git a/packages/amplify-cli/src/extensions/amplify-helpers/push-resources.ts b/packages/amplify-cli/src/extensions/amplify-helpers/push-resources.ts index 3e3c5efa8b0..0101ae75c5b 100644 --- a/packages/amplify-cli/src/extensions/amplify-helpers/push-resources.ts +++ b/packages/amplify-cli/src/extensions/amplify-helpers/push-resources.ts @@ -6,6 +6,7 @@ import { getProviderPlugins } from './get-provider-plugins'; import { getEnvInfo } from './get-env-info'; import { EnvironmentDoesNotExistError, exitOnNextTick, stateManager, $TSAny, $TSContext, CustomPoliciesFormatError } from 'amplify-cli-core'; import { printer } from 'amplify-prompts'; +import { promptSandboxModeApiKey } from './prompt-sandbox-mode-api-key'; export async function pushResources( context: $TSContext, @@ -68,6 +69,8 @@ export async function pushResources( continueToPush = await context.amplify.confirmPrompt('Are you sure you want to continue?'); } + await promptSandboxModeApiKey(context); + if (continueToPush) { try { // Get current-cloud-backend's amplify-meta diff --git a/packages/amplify-cli/src/extensions/amplify-helpers/show-global-sandbox-mode-warning.ts b/packages/amplify-cli/src/extensions/amplify-helpers/show-global-sandbox-mode-warning.ts new file mode 100644 index 00000000000..c3171b8a666 --- /dev/null +++ b/packages/amplify-cli/src/extensions/amplify-helpers/show-global-sandbox-mode-warning.ts @@ -0,0 +1,31 @@ +import chalk from 'chalk'; +import { $TSContext } from 'amplify-cli-core'; +import { getAppSyncApiConfig, getApiKeyConfig } from './get-api-key-config'; + +export function globalSandboxModeEnabled(context: $TSContext): boolean { + const appSyncApi = getAppSyncApiConfig(); + const currEnvName = context.amplify.getEnvInfo().envName; + const { globalSandboxModeConfig } = appSyncApi?.output || {}; + + if (!globalSandboxModeConfig) return false; + + return globalSandboxModeConfig.env === currEnvName; +} + +export function showGlobalSandboxModeWarning(context: $TSContext): void { + const apiKeyConfig = getApiKeyConfig(); + + if (!apiKeyConfig?.apiKeyExpirationDate) return; + + const expirationDate = new Date(apiKeyConfig.apiKeyExpirationDate); + + if (apiKeyConfig && globalSandboxModeEnabled(context)) { + context.print.info(` +${chalk.yellow(`⚠️ WARNING: ${chalk.green('"type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key"')} in your GraphQL schema +allows public create, read, update, and delete access to all models via API Key. This +should only be used for testing purposes. API Key expiration date is: ${expirationDate.toLocaleDateString()} + +To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth`)} +`); + } +} diff --git a/packages/amplify-e2e-tests/schemas/model_with_sandbox_mode.graphql b/packages/amplify-e2e-tests/schemas/model_with_sandbox_mode.graphql new file mode 100644 index 00000000000..22c833e9c67 --- /dev/null +++ b/packages/amplify-e2e-tests/schemas/model_with_sandbox_mode.graphql @@ -0,0 +1,6 @@ +type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: "dev") + +type Todo @model { + id: ID! + content: String +} diff --git a/packages/amplify-e2e-tests/src/__tests__/sandbox-mode.test.ts b/packages/amplify-e2e-tests/src/__tests__/sandbox-mode.test.ts new file mode 100644 index 00000000000..f16ac9e5cee --- /dev/null +++ b/packages/amplify-e2e-tests/src/__tests__/sandbox-mode.test.ts @@ -0,0 +1,45 @@ +import { + initJSProjectWithProfile, + deleteProject, + createNewProjectDir, + deleteProjectDir, + addApiWithSchema, + amplifyPush, + getProjectMeta, +} from 'amplify-e2e-core'; +import { testSchema } from '../schema-api-directives'; + +describe('api directives @allow_public_data_access_with_api_key', () => { + let projectDir: string; + const envName = 'dev'; + + beforeEach(async () => { + projectDir = await createNewProjectDir('model'); + await initJSProjectWithProfile(projectDir, { envName }); + }); + + afterEach(async () => { + await deleteProject(projectDir); + deleteProjectDir(projectDir); + }); + + it('schema and files generate with sandbox mode', async () => { + await addApiWithSchema(projectDir, 'model_with_sandbox_mode.graphql'); + await amplifyPush(projectDir); + + const meta = getProjectMeta(projectDir); + const { output } = meta.api.simplemodel; + const { authConfig, globalSandboxModeConfig, GraphQLAPIIdOutput, GraphQLAPIEndpointOutput, GraphQLAPIKeyOutput } = output; + + expect(globalSandboxModeConfig.env).toBeDefined(); + expect(authConfig.defaultAuthentication.authenticationType).toBe('API_KEY'); + expect(authConfig.defaultAuthentication.apiKeyConfig.apiKeyExpirationDate).toBeDefined(); + + expect(GraphQLAPIIdOutput).toBeDefined(); + expect(GraphQLAPIEndpointOutput).toBeDefined(); + expect(GraphQLAPIKeyOutput).toBeDefined(); + + const testresult = await testSchema(projectDir, 'model', 'generates'); + expect(testresult).toBeTruthy(); + }); +}); diff --git a/packages/amplify-graphql-auth-transformer/.npmignore b/packages/amplify-graphql-auth-transformer/.npmignore new file mode 100644 index 00000000000..3ee5d55b0b8 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/.npmignore @@ -0,0 +1,5 @@ +**/__mocks__/** +**/__tests__/** +src +tsconfig.json +tsconfig.tsbuildinfo diff --git a/packages/amplify-graphql-auth-transformer/CHANGELOG.md b/packages/amplify-graphql-auth-transformer/CHANGELOG.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/amplify-graphql-auth-transformer/package.json b/packages/amplify-graphql-auth-transformer/package.json new file mode 100644 index 00000000000..f8e49efdfbb --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/package.json @@ -0,0 +1,67 @@ +{ + "name": "@aws-amplify/graphql-auth-transformer", + "version": "0.1.0", + "description": "Amplify GraphQL @auth Transformer", + "repository": { + "type": "git", + "url": "https://github.com/aws-amplify/amplify-cli.git", + "directory": "packages/amplify-graphql-auth-transformer" + }, + "author": "Amazon Web Services", + "license": "Apache-2.0", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "keywords": [ + "graphql", + "cloudformation", + "aws", + "amplify" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "test": "jest", + "build": "tsc", + "clean": "rimraf ./lib", + "watch": "tsc -w" + }, + "dependencies": { + "@aws-amplify/graphql-transformer-core": "0.9.0", + "@aws-amplify/graphql-transformer-interfaces": "1.9.0", + "@aws-amplify/graphql-model-transformer": "0.6.2", + "@aws-cdk/aws-appsync": "~1.119.0", + "@aws-cdk/aws-dynamodb": "~1.119.0", + "@aws-cdk/core": "~1.119.0", + "@aws-cdk/aws-iam": "~1.119.0", + "constructs": "^3.3.125", + "graphql": "^14.5.8", + "graphql-mapping-template": "4.18.3", + "graphql-transformer-common": "4.19.9", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@aws-amplify/graphql-index-transformer": "0.3.2", + "@aws-amplify/graphql-relational-transformer": "0.2.1", + "@aws-amplify/graphql-searchable-transformer": "0.6.0", + "@types/fs-extra": "^8.0.1", + "@aws-cdk/assert": "~1.72.0", + "@types/node": "^12.12.6" + }, + "jest": { + "testURL": "http://localhost", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testRegex": "(src/__tests__/.*.test.ts)$", + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx", + "json", + "node" + ], + "collectCoverage": true + } +} diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/__snapshots__/field-auth-argument.test.ts.snap b/packages/amplify-graphql-auth-transformer/src/__tests__/__snapshots__/field-auth-argument.test.ts.snap new file mode 100644 index 00000000000..0a0706bd49e --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/__snapshots__/field-auth-argument.test.ts.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`per-field @auth without @model 1`] = ` +Object { + "Properties": Object { + "Description": "", + "Path": "/", + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "appsync:GraphQL", + "Effect": "Allow", + "Resource": Object { + "Fn::Sub": Array [ + "arn:aws:appsync:\${AWS::Region}:\${AWS::AccountId}:apis/\${apiId}/types/\${typeName}/fields/\${fieldName}", + Object { + "apiId": Object { + "Fn::GetAtt": Array [ + "GraphQLAPI", + "ApiId", + ], + }, + "fieldName": "listContext", + "typeName": "Query", + }, + ], + }, + }, + ], + "Version": "2012-10-17", + }, + "Roles": Array [ + Object { + "Ref": "authRoleName", + }, + ], + }, + "Type": "AWS::IAM::ManagedPolicy", +} +`; diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/accesscontrol.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/accesscontrol.test.ts new file mode 100644 index 00000000000..6aa2d0e9ecf --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/accesscontrol.test.ts @@ -0,0 +1,112 @@ +import { AccessControlMatrix } from '../accesscontrol'; +import { MODEL_OPERATIONS } from '../utils'; + +test('test access control on object and field', () => { + /* + given the following schema + type Student + @model + @auth(rules: [ + { allow: groups, groups: ["admin"] } + { allow: groups, groups: ["student"], operations: [read] } + ]) { + studentID: ID + name: String + #acm protect email only studentID can update their own email + email: AWSEmail @auth(rules: [ + { allow: owner, ownerField: "studentID", operations: [update] } + { allow: groups, groups: ["admin"] } + ]) + # only allowed to student and admin + ssn: String @auth(rules: [ + { allow: owner, ownerField: "studentID", operations: [read] } + { allow: groups, groups: ["admin"] } + ]) + } + */ + // create an acm for the student type + const adminRole = 'userPools:staticGroup:admin'; + const studentGroupRole = 'userPools:staticGroup:student'; + const studentOwnerRole = 'userPools:owner:studentID'; + const studentTypeFields = ['studentID', 'name', 'email', 'ssn']; + const acm = new AccessControlMatrix({ + resources: studentTypeFields, + operations: MODEL_OPERATIONS, + }); + // add OBJECT rules first + // add admin role which has full access on all CRUD operations for all fields + acm.setRole({ + role: adminRole, + operations: MODEL_OPERATIONS, + }); + // add the student static group rule which only has read access + acm.setRole({ + role: studentGroupRole, + operations: ['read'], + }); + + studentTypeFields.forEach(field => { + // check that admin has CRUD access on all fields + expect(acm.isAllowed(adminRole, field, 'create')).toBe(true); + expect(acm.isAllowed(adminRole, field, 'read')).toBe(true); + expect(acm.isAllowed(adminRole, field, 'update')).toBe(true); + expect(acm.isAllowed(adminRole, field, 'delete')).toBe(true); + // check that studentGroupRole has access to read only + expect(acm.isAllowed(studentGroupRole, field, 'read')).toBe(true); + expect(acm.isAllowed(studentGroupRole, field, 'create')).toBe(false); + expect(acm.isAllowed(studentGroupRole, field, 'update')).toBe(false); + expect(acm.isAllowed(studentGroupRole, field, 'delete')).toBe(false); + }); + // when adding a field rule on email we need to overwrite it + acm.resetAccessForResource('email'); + + expect(acm.isAllowed(studentGroupRole, 'email', 'read')).toBe(false); + acm.setRole({ + role: studentOwnerRole, + operations: ['update'], + resource: 'email', + }); + expect(acm.isAllowed(adminRole, 'email', 'update')).toBe(false); + expect(acm.isAllowed(studentOwnerRole, 'email', 'update')).toBe(true); +}); + +test('test access control only on field', () => { + /* + given the following schema + type Student + @model { + studentID: ID + name: String + # only allows read access on email and ssn for studentID ownerfield can also only update email + email: AWSEmail @auth(rules: [ + { allow: owner, ownerField: "studentID", operations: [read, update] } + ]) + ssn: String @auth(rules: [ + { allow: owner, ownerField: "studentID", operations: [read] } + ]) + } + */ + // create an acm for the student type + const studentOwnerRole = 'userPools:owner:studentID'; + const studentTypeFields = ['studentID', 'name', 'email', 'ssn']; + const acm = new AccessControlMatrix({ + resources: studentTypeFields, + operations: MODEL_OPERATIONS, + }); + // set role for email field + acm.setRole({ role: studentOwnerRole, operations: ['read', 'update'], resource: 'email' }); + // set role for ssn field + acm.setRole({ role: studentOwnerRole, operations: ['read'], resource: 'ssn' }); + + // expect the correct permissions are assigned for email field + expect(acm.isAllowed(studentOwnerRole, 'email', 'update')).toBe(true); + expect(acm.isAllowed(studentOwnerRole, 'email', 'read')).toBe(true); + expect(acm.isAllowed(studentOwnerRole, 'email', 'delete')).toBe(false); + expect(acm.isAllowed(studentOwnerRole, 'email', 'create')).toBe(false); + + // expect the correct permissions are assigned for ssn field + expect(acm.isAllowed(studentOwnerRole, 'ssn', 'create')).toBe(false); + expect(acm.isAllowed(studentOwnerRole, 'ssn', 'read')).toBe(true); + expect(acm.isAllowed(studentOwnerRole, 'ssn', 'update')).toBe(false); + expect(acm.isAllowed(studentOwnerRole, 'ssn', 'delete')).toBe(false); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/amplify-admin-auth.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/amplify-admin-auth.test.ts new file mode 100644 index 00000000000..ce358a0143e --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/amplify-admin-auth.test.ts @@ -0,0 +1,337 @@ +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import _ from 'lodash'; + +test('test simple model with public auth rule and amplify admin app is present', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: public}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + }`; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'API_KEY', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: true, + adminUserPoolID: 'us-fake-1_uuid', + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).toContain('Post @aws_api_key @aws_iam'); +}); + +test('Test simple model with public auth rule and amplify admin app is not enabled', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: public}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'API_KEY', + }, + additionalAuthenticationProviders: [], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).not.toContain('Post @aws_api_key @aws_iam'); +}); + +test('Test model with public auth rule without all operations and amplify admin app is present', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: public, operations: [read, update]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'API_KEY', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: true, + adminUserPoolID: 'us-fake-1_uuid', + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + expect(out.schema).toContain('type Post @aws_iam @aws_api_key'); + expect(out.schema).toContain('createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post @aws_api_key @aws_iam'); + expect(out.schema).toContain('updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post @aws_api_key @aws_iam'); + expect(out.schema).toContain('deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post @aws_api_key @aws_iam'); + + // No Resource extending Auth and UnAuth role + const policyResources = Object.values(out.rootStack.Resources!).filter(r => r.Type === 'AWS::IAM::ManagedPolicy'); + expect(policyResources).toHaveLength(0); +}); + +test('Test simple model with private auth rule and amplify admin app is present', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: true, + adminUserPoolID: 'us-fake-1_uuid', + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).toContain('type Post @aws_iam @aws_cognito_user_pools'); +}); + +test('Test simple model with private auth rule and amplify admin app not enabled', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).not.toContain('type Post @aws_iam @aws_cognito_user_pools'); +}); + +test('Test simple model with private auth rule, few operations, and amplify admin app enabled', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"], operations: [read]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig: { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + addAwsIamAuthInOutputSchema: true, + adminUserPoolID: 'us-fake-1_uuid', + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).toContain('type Post @aws_iam @aws_cognito_user_pools'); + expect(out.schema).toContain( + 'createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + expect(out.schema).toContain( + 'updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + expect(out.schema).toContain( + 'deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + + // No Resource extending Auth and UnAuth role + const policyResources = Object.values(out.rootStack.Resources!).filter(r => r.Type === 'AWS::IAM::ManagedPolicy'); + expect(policyResources).toHaveLength(0); +}); + +test('Test simple model with private IAM auth rule, few operations, and amplify admin app is not enabled', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: private, provider: iam, operations: [read]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).toContain('Post @aws_iam'); + expect(out.schema).not.toContain( + 'createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + expect(out.schema).not.toContain('deletePost(input: DeletePostInput!): Post @aws_iam'); + expect(out.schema).not.toContain('updatePost(input: UpdatePostInput!): Post @aws_iam'); + + expect(out.schema).toContain('getPost(id: ID!): Post @aws_iam'); + expect(out.schema).toContain('listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection @aws_iam'); +}); + +test('Test simple model with AdminUI enabled should add IAM policy only for fields that have explicit IAM auth', () => { + const validSchema = ` + type Post @model @auth(rules: [{allow: private, provider: iam, operations: [read]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig: { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'AWS_IAM', + }, + ], + }, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + addAwsIamAuthInOutputSchema: true, + adminUserPoolID: 'us-fake-1_uuid', + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).toContain('Post @aws_iam @aws_cognito_user_pool'); + expect(out.schema).toContain( + 'createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + expect(out.schema).toContain( + 'updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + expect(out.schema).toContain( + 'deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post @aws_iam @aws_cognito_user_pools', + ); + + expect(out.schema).toContain('getPost(id: ID!): Post @aws_iam'); + expect(out.schema).toContain('listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection @aws_iam'); + const policyResources = _.filter(out.rootStack.Resources, r => r.Type === 'AWS::IAM::ManagedPolicy'); + expect(policyResources).toHaveLength(1); + const resources = _.get(policyResources, '[0].Properties.PolicyDocument.Statement[0].Resource'); + const typeFieldList = _.map(resources, r => _.get(r, 'Fn::Sub[1]')).map(r => `${_.get(r, 'typeName')}.${_.get(r, 'fieldName', '*')}`); + expect(typeFieldList).toEqual([ + 'Post.*', + 'Query.getPost', + 'Query.listPosts', + 'Mutation.createPost', + 'Mutation.updatePost', + 'Mutation.deletePost', + 'Subscription.onCreatePost', + 'Subscription.onUpdatePost', + 'Subscription.onDeletePost', + ]); + // should throw unauthorized if it's not signed by the admin ui iam role + ['Mutation.createPost.auth.1.req.vtl', 'Mutation.updatePost.auth.1.res.vtl', 'Mutation.deletePost.auth.1.res.vtl'].forEach(r => { + expect(out.pipelineFunctions[r]).toContain( + '#if( $util.authType() == "IAM Authorization" )\n' + + ' #if( $ctx.identity.userArn.contains("us-fake-1_uuid_Full-access/CognitoIdentityCredentials") || $ctx.identity.userArn.contains("us-fake-1_uuid_Manage-only/CognitoIdentityCredentials") )\n' + + ' #return($util.toJson({})\n' + + ' #end\n' + + '$util.unauthorized()\n' + + '#end', + ); + }); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/field-auth-argument.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/field-auth-argument.test.ts new file mode 100644 index 00000000000..5a30bfda709 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/field-auth-argument.test.ts @@ -0,0 +1,118 @@ +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { HasManyTransformer } from '@aws-amplify/graphql-relational-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; + +test('subscriptions are only generated if the respective mutation operation exists', () => { + const validSchema = ` + type Salary + @model + @auth(rules: [ + {allow: owner}, + {allow: groups, groups: ["Moderator"]} + ]) { + id: ID! + wage: Int + owner: String + secret: String @auth(rules: [{allow: owner}]) + }`; + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new HasManyTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + // expect to generate subscription resolvers for create and update only + expect(out).toBeDefined(); + expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( + 'AMAZON_COGNITO_USER_POOLS', + ); + expect(out.pipelineFunctions['Salary.secret.res.vtl']).toContain('#if( $operation == "Mutation" )'); + + expect(out.pipelineFunctions['Mutation.createSalary.res.vtl']).toContain('$util.qr($ctx.result.put("__operation", "Mutation"))'); + expect(out.pipelineFunctions['Mutation.updateSalary.res.vtl']).toContain('$util.qr($ctx.result.put("__operation", "Mutation"))'); + expect(out.pipelineFunctions['Mutation.deleteSalary.res.vtl']).toContain('$util.qr($ctx.result.put("__operation", "Mutation"))'); +}); + +test('per-field auth on relational field', () => { + const validSchema = ` + type Post @model @auth(rules: [ { allow: groups, groups: ["admin"] }, { allow: groups, groups: ["viewer"], operations: [read] } ]){ + id: ID! + title: String! + comments: [Comment] @hasMany @auth(rules: [ { allow: groups, groups: ["admin"] } ]) + } + + type Comment @model { + id: ID! + content: String + }`; + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [{ authenticationType: 'AWS_IAM' }], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new HasManyTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + expect(out.pipelineFunctions['Post.comments.auth.1.req.vtl']).toContain( + '#set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"admin"}] )', + ); +}); + +test('per-field @auth without @model', () => { + const validSchema = ` + type Query { + listContext: String @auth(rules: [{ allow: groups, groups: ["Allowed"] }, { allow: private, provider: iam }]) + }`; + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [{ authenticationType: 'AWS_IAM' }], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + const resources = out.rootStack.Resources; + const authPolicyIdx = Object.keys(out.rootStack.Resources).find(r => r.includes('AuthRolePolicy')); + expect(resources[authPolicyIdx]).toMatchSnapshot(); + expect(out.pipelineFunctions['Query.listContext.req.vtl']).toContain( + '#set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"Allowed"}] )', + ); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/group-auth.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/group-auth.test.ts new file mode 100644 index 00000000000..6bf8f548ac8 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/group-auth.test.ts @@ -0,0 +1,97 @@ +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; + +test('happy case with static groups', () => { + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const validSchema = ` + type Post @model @auth(rules: [{allow: groups, groups: ["Admin", "Dev"]}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + }`; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.rootStack!.Resources![ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( + 'AMAZON_COGNITO_USER_POOLS', + ); +}); + +test('happy case with dynamic groups', () => { + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const validSchema = ` + type Post @model @auth(rules: [{allow: groups, groupsField: "groups"}]) { + id: ID! + title: String! + groups: [String] + createdAt: String + updatedAt: String + } + `; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.rootStack!.Resources![ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( + 'AMAZON_COGNITO_USER_POOLS', + ); +}); + +test('validation on @auth on a non-@model type', () => { + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const invalidSchema = ` + type Post @auth(rules: [{allow: groups, groupsField: "groups"}]) { + id: ID! + title: String! + group: String + createdAt: String + updatedAt: String + }`; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + expect(() => transformer.transform(invalidSchema)).toThrowError('Types annotated with @auth must also be annotated with @model.'); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/multi-auth.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/multi-auth.test.ts new file mode 100644 index 00000000000..620824ea105 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/multi-auth.test.ts @@ -0,0 +1,683 @@ +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { IndexTransformer } from '@aws-amplify/graphql-index-transformer'; +import { HasManyTransformer, HasOneTransformer, BelongsToTransformer } from '@aws-amplify/graphql-relational-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import { AppSyncAuthConfiguration, AppSyncAuthConfigurationOIDCEntry, AppSyncAuthMode } from '@aws-amplify/graphql-transformer-interfaces'; +import { DocumentNode, ObjectTypeDefinitionNode, Kind, FieldDefinitionNode, parse, InputValueDefinitionNode } from 'graphql'; + +const userPoolsDefaultConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], +}; + +const apiKeyDefaultConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'API_KEY', + }, + additionalAuthenticationProviders: [], +}; + +const iamDefaultConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AWS_IAM', + }, + additionalAuthenticationProviders: [], +}; + +const withAuthModes = (authConfig: AppSyncAuthConfiguration, authModes: AppSyncAuthMode[]): AppSyncAuthConfiguration => { + const newAuthConfig = { + defaultAuthentication: { + authenticationType: authConfig.defaultAuthentication.authenticationType, + }, + additionalAuthenticationProviders: [], + }; + + for (const authMode of authModes) { + newAuthConfig.additionalAuthenticationProviders.push({ + authenticationType: authMode, + }); + } + + return newAuthConfig; +}; + +const apiKeyDirectiveName = 'aws_api_key'; +const userPoolsDirectiveName = 'aws_cognito_user_pools'; +const iamDirectiveName = 'aws_iam'; +const openIdDirectiveName = 'aws_oidc'; + +const multiAuthDirective = + '@auth(rules: [{allow: private}, {allow: public}, {allow: private, provider: iam }, {allow: owner, provider: oidc }])'; +const ownerAuthDirective = '@auth(rules: [{allow: owner}])'; +const ownerWithIAMAuthDirective = '@auth(rules: [{allow: owner, provider: iam }])'; +const ownerRestrictedPublicAuthDirective = '@auth(rules: [{allow: owner},{allow: public, operations: [read]}])'; +const ownerRestrictedIAMPrivateAuthDirective = '@auth(rules: [{allow: owner},{allow: private, operations: [read], provider: iam }])'; +const groupsAuthDirective = '@auth(rules: [{allow: groups, groups: ["admin"] }])'; +const groupsWithApiKeyAuthDirective = '@auth(rules: [{allow: groups, groups: ["admin"]}, {allow: public, operations: [read]}])'; +const groupsWithProviderAuthDirective = '@auth(rules: [{allow: groups,groups: ["admin"], provider: iam }])'; +const ownerOpenIdAuthDirective = '@auth(rules: [{allow: owner, provider: oidc }])'; +const privateAuthDirective = '@auth(rules: [{allow: private}])'; +const publicIAMAuthDirective = '@auth(rules: [{allow: public, provider: iam }])'; +const privateWithApiKeyAuthDirective = '@auth(rules: [{allow: private, provider: apiKey }])'; +const publicAuthDirective = '@auth(rules: [{allow: public}])'; +const publicUserPoolsAuthDirective = '@auth(rules: [{allow: public, provider: userPools}])'; +const privateAndPublicDirective = '@auth(rules: [{allow: private}, {allow: public}])'; +const privateIAMDirective = '@auth(rules: [{allow: private, provider: iam}])'; +// const privateAndPrivateIAMDirective = '@auth(rules: [{allow: private}, {allow: private, provider: iam}])'; + +const getSchema = (authDirective: string) => { + return ` + type Post @model ${authDirective} { + id: ID! + title: String! + createdAt: String + updatedAt: String + }`; +}; + +const getSchemaWithFieldAuth = (authDirective: string) => { + return ` + type Post @model { + id: ID + title: String + createdAt: String + updatedAt: String + protected: String ${authDirective} + }`; +}; + +const getSchemaWithTypeAndFieldAuth = (typeAuthDirective: string, fieldAuthDirective: string) => { + return ` + type Post @model ${typeAuthDirective} { + id: ID + title: String + createdAt: String + updatedAt: String + protected: String ${fieldAuthDirective} + }`; +}; + +const getSchemaWithNonModelField = (authDirective: string) => { + return ` + type Post @model ${authDirective} { + id: ID! + title: String! + location: Location + status: Status + createdAt: String + updatedAt: String + } + + type Location { + name: String + address: Address + } + + type Address { + street: String + city: String + state: String + zip: String + } + + enum Status { + PUBLISHED, + DRAFT + }`; +}; + +const getSchemaWithRecursiveNonModelField = (authDirective: string) => { + return ` + type Post @model ${authDirective} { + id: ID! + title: String! + tags: [Tag] + } + + type Tag { + id: ID + tags: [Tag] + } + `; +}; + +const getRecursiveSchemaWithDiffModesOnParentType = (authDir1: string, authDir2: string) => { + return ` + type Post @model ${authDir1} { + id: ID! + title: String! + tags: [Tag] + } + + type Comment @model ${authDir2} { + id: ID! + content: String + tags: [Tag] + } + + type Tag { + id: ID + tags: [Tag] + } + `; +}; + +const getTransformer = (authConfig: AppSyncAuthConfiguration) => + new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new IndexTransformer(), + new HasManyTransformer(), + new HasOneTransformer(), + new BelongsToTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + +const getObjectType = (doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined => { + return doc.definitions.find(def => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as + | ObjectTypeDefinitionNode + | undefined; +}; + +const expectNone = fieldOrType => { + expect(fieldOrType.directives.length === 0); +}; + +const expectOne = (fieldOrType, directiveName) => { + expect(fieldOrType.directives.length).toBe(1); + expect(fieldOrType.directives.find(d => d.name.value === directiveName)).toBeDefined(); +}; + +const expectTwo = (fieldOrType, directiveNames) => { + expect(directiveNames).toBeDefined(); + expect(directiveNames).toHaveLength(2); + expect(fieldOrType.directives.length === 2); + expect(fieldOrType.directives.find(d => d.name.value === directiveNames[0])).toBeDefined(); + expect(fieldOrType.directives.find(d => d.name.value === directiveNames[1])).toBeDefined(); +}; + +const expectMultiple = (fieldOrType: ObjectTypeDefinitionNode | FieldDefinitionNode, directiveNames: string[]) => { + expect(directiveNames).toBeDefined(); + expect(directiveNames).toHaveLength(directiveNames.length); + expect(fieldOrType.directives.length).toEqual(directiveNames.length); + directiveNames.forEach(directiveName => { + expect(fieldOrType.directives).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: expect.objectContaining({ value: directiveName }), + }), + ]), + ); + }); +}; + +const getField = (type, name) => type.fields.find(f => f.name.value === name); + +describe('validation tests', () => { + const validationTest = (authDirective, authConfig, expectedError) => { + const schema = getSchema(authDirective); + const transformer = getTransformer(authConfig); + + const t = () => { + const out = transformer.transform(schema); + }; + + expect(t).toThrowError(expectedError); + }; + + test('AMAZON_COGNITO_USER_POOLS not configured for project', () => { + validationTest( + privateAuthDirective, + apiKeyDefaultConfig, + `@auth directive with 'userPools' provider found, but the project has no Cognito User \ +Pools authentication provider configured.`, + ); + }); + + test('API_KEY not configured for project', () => { + validationTest( + publicAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'apiKey' provider found, but the project has no API Key \ +authentication provider configured.`, + ); + }); + + test('AWS_IAM not configured for project', () => { + validationTest( + publicIAMAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'iam' provider found, but the project has no IAM \ +authentication provider configured.`, + ); + }); + + test('OPENID_CONNECT not configured for project', () => { + validationTest( + ownerOpenIdAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'oidc' provider found, but the project has no OPENID_CONNECT \ +authentication provider configured.`, + ); + }); + + test(`'group' cannot have provider`, () => { + validationTest( + groupsWithProviderAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'groups' strategy only supports 'userPools' and 'oidc' providers, but found \ +'iam' assigned`, + ); + }); + + test(`'owner' has invalid IAM provider`, () => { + validationTest( + ownerWithIAMAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'owner' strategy only supports 'userPools' (default) and \ +'oidc' providers, but found 'iam' assigned.`, + ); + }); + + test(`'public' has invalid 'userPools' provider`, () => { + validationTest( + publicUserPoolsAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'public' strategy only supports 'apiKey' (default) and 'iam' providers, but \ +found 'userPools' assigned.`, + ); + }); + + test(`'private' has invalid 'apiKey' provider`, () => { + validationTest( + privateWithApiKeyAuthDirective, + userPoolsDefaultConfig, + `@auth directive with 'private' strategy only supports 'userPools' (default) and 'iam' providers, but \ +found 'apiKey' assigned.`, + ); + }); +}); + +describe('schema generation directive tests', () => { + const transformTest = (authDirective, authConfig, expectedDirectiveNames?: string[] | undefined) => { + const schema = getSchema(authDirective); + const transformer = getTransformer(authConfig); + + const out = transformer.transform(schema); + + const schemaDoc = parse(out.schema); + + const postType = getObjectType(schemaDoc, 'Post'); + + if (expectedDirectiveNames && expectedDirectiveNames.length > 0) { + let expectedDireciveNameCount = 0; + + for (const expectedDirectiveName of expectedDirectiveNames) { + expect(postType.directives.find(d => d.name.value === expectedDirectiveName)).toBeDefined(); + expectedDireciveNameCount++; + } + + expect(expectedDireciveNameCount).toEqual(postType.directives.length); + } + }; + + test(`When provider is the same as default, then no directive added`, () => { + transformTest(ownerAuthDirective, userPoolsDefaultConfig); + }); + + test(`When all providers are configured all of them are added`, () => { + const authConfig = withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS', 'AWS_IAM', 'OPENID_CONNECT']); + + (authConfig.additionalAuthenticationProviders[2] as AppSyncAuthConfigurationOIDCEntry).openIDConnectConfig = { + name: 'Test Provider', + issuerUrl: 'https://abc.def/', + }; + + transformTest(multiAuthDirective, authConfig, [userPoolsDirectiveName, iamDirectiveName, openIdDirectiveName, apiKeyDirectiveName]); + }); + + test(`Operation fields are getting the directive added, when type has the @auth for all operations`, () => { + const schema = getSchema(ownerAuthDirective); + const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + const queryType = getObjectType(schemaDoc, 'Query'); + const mutationType = getObjectType(schemaDoc, 'Mutation'); + const subscriptionType = getObjectType(schemaDoc, 'Subscription'); + + const fields = [...queryType.fields, ...mutationType.fields]; + + for (const field of fields) { + expect(field.directives.length === 1); + expect(field.directives.find(d => d.name.value === userPoolsDirectiveName)).toBeDefined(); + } + + // Check that owner is required when only using owner auth rules + for (const field of subscriptionType.fields) { + expect(field.arguments).toHaveLength(1); + let arg: InputValueDefinitionNode = field.arguments[0]; + expect(arg.name.value).toEqual('owner'); + expect(arg.type.kind).toEqual(Kind.NAMED_TYPE); + } + + // Check that resolvers containing the authMode check block + const authStepSnippet = '## [Start] Authorization Steps. **'; + + expect(out.pipelineFunctions['Query.getPost.auth.1.req.vtl']).toContain(authStepSnippet); + expect(out.pipelineFunctions['Query.listPosts.auth.1.req.vtl']).toContain(authStepSnippet); + expect(out.pipelineFunctions['Mutation.createPost.auth.1.req.vtl']).toContain(authStepSnippet); + expect(out.pipelineFunctions['Mutation.createPost.auth.1.req.vtl']).toContain(authStepSnippet); + expect(out.pipelineFunctions['Mutation.updatePost.auth.1.res.vtl']).toContain(authStepSnippet); + expect(out.pipelineFunctions['Mutation.deletePost.auth.1.res.vtl']).toContain(authStepSnippet); + }); + + test(`Operation fields are getting the directive added, when type has the @auth only for allowed operations`, () => { + const schema = getSchema(ownerRestrictedPublicAuthDirective); + const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + const queryType = getObjectType(schemaDoc, 'Query'); + const mutationType = getObjectType(schemaDoc, 'Mutation'); + const subscriptionType = getObjectType(schemaDoc, 'Subscription'); + + expectTwo(getField(queryType, 'getPost'), ['aws_cognito_user_pools', 'aws_api_key']); + expectTwo(getField(queryType, 'listPosts'), ['aws_cognito_user_pools', 'aws_api_key']); + + expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools'); + + const onCreate = getField(subscriptionType, 'onCreatePost'); + expectMultiple(onCreate, ['aws_subscribe', 'aws_api_key', 'aws_cognito_user_pools']); + expectMultiple(getField(subscriptionType, 'onUpdatePost'), ['aws_subscribe', 'aws_api_key', 'aws_cognito_user_pools']); + expectMultiple(getField(subscriptionType, 'onDeletePost'), ['aws_subscribe', 'aws_api_key', 'aws_cognito_user_pools']); + expect(onCreate.arguments).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: expect.objectContaining({ value: 'owner' }), + type: expect.objectContaining({ kind: 'NamedType' }), + }), + ]), + ); + }); + + test(`Field level @auth is propagated to type and the type related operations`, () => { + const schema = getSchemaWithFieldAuth(ownerRestrictedPublicAuthDirective); + const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + const queryType = getObjectType(schemaDoc, 'Query'); + const mutationType = getObjectType(schemaDoc, 'Mutation'); + + expectTwo(getField(queryType, 'getPost'), ['aws_cognito_user_pools', 'aws_api_key']); + expectTwo(getField(queryType, 'listPosts'), ['aws_cognito_user_pools', 'aws_api_key']); + + expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); + // since there is only one field allowed on delete it does not have access to delete + expectNone(getField(mutationType, 'deletePost')); + + // Check that resolvers containing the authMode check block + const authModeCheckSnippet = '## [Start] Field Authorization Steps. **'; + // resolvers to check is all other resolvers other than protected + expect(out.pipelineFunctions['Post.id.req.vtl']).toContain(authModeCheckSnippet); + expect(out.pipelineFunctions['Post.title.req.vtl']).toContain(authModeCheckSnippet); + expect(out.pipelineFunctions['Post.createdAt.req.vtl']).toContain(authModeCheckSnippet); + expect(out.pipelineFunctions['Post.updatedAt.req.vtl']).toContain(authModeCheckSnippet); + }); + + test(`'groups' @auth at field level is propagated to type and the type related operations`, () => { + const schema = getSchemaWithFieldAuth(groupsAuthDirective); + const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + const queryType = getObjectType(schemaDoc, 'Query'); + const mutationType = getObjectType(schemaDoc, 'Mutation'); + + expectOne(getField(queryType, 'getPost'), 'aws_cognito_user_pools'); + expectOne(getField(queryType, 'listPosts'), 'aws_cognito_user_pools'); + + expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); + // since there is only one field allowed on delete it does not have access to delete + expectNone(getField(mutationType, 'deletePost')); + + // Check that resolvers containing the authMode check block + const authModeCheckSnippet = '## [Start] Field Authorization Steps. **'; + + // resolvers to check is all other resolvers other than protected + expect(out.pipelineFunctions['Post.id.req.vtl']).toContain(authModeCheckSnippet); + expect(out.pipelineFunctions['Post.title.req.vtl']).toContain(authModeCheckSnippet); + expect(out.pipelineFunctions['Post.createdAt.req.vtl']).toContain(authModeCheckSnippet); + expect(out.pipelineFunctions['Post.updatedAt.req.vtl']).toContain(authModeCheckSnippet); + }); + + test(`'groups' @auth at field level is propagated to type and the type related operations, also default provider for read`, () => { + const schema = getSchemaWithTypeAndFieldAuth(groupsAuthDirective, groupsWithApiKeyAuthDirective); + const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + const queryType = getObjectType(schemaDoc, 'Query'); + const mutationType = getObjectType(schemaDoc, 'Mutation'); + + expectTwo(getField(queryType, 'getPost'), ['aws_cognito_user_pools', 'aws_api_key']); + expectTwo(getField(queryType, 'listPosts'), ['aws_cognito_user_pools', 'aws_api_key']); + + expectOne(getField(mutationType, 'createPost'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'updatePost'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'deletePost'), 'aws_cognito_user_pools'); + + // Check that resolvers containing the authMode group check + const groupCheckSnippet = '#set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"admin"}] )'; + + // resolvers to check is all other resolvers other than protected by the group rule + expect(out.pipelineFunctions['Post.id.req.vtl']).toContain(groupCheckSnippet); + expect(out.pipelineFunctions['Post.title.req.vtl']).toContain(groupCheckSnippet); + expect(out.pipelineFunctions['Post.createdAt.req.vtl']).toContain(groupCheckSnippet); + expect(out.pipelineFunctions['Post.updatedAt.req.vtl']).toContain(groupCheckSnippet); + }); + + test(`Nested types without @model not getting directives applied for iam, and no policy is generated`, () => { + const schema = getSchemaWithNonModelField(''); + const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + + const locationType = getObjectType(schemaDoc, 'Location'); + const addressType = getObjectType(schemaDoc, 'Address'); + + expect(locationType.directives.length).toBe(0); + expect(addressType.directives.length).toBe(0); + + const authPolicyIdx = Object.keys(out.rootStack.Resources).find(r => r.includes('AuthRolePolicy')); + + expect(out.rootStack.Resources[authPolicyIdx]).toBeUndefined(); + }); + + test(`Nested types without @model not getting directives applied for iam, but policy is generated`, () => { + const schema = getSchemaWithNonModelField(privateIAMDirective); + const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + + const locationType = getObjectType(schemaDoc, 'Location'); + const addressType = getObjectType(schemaDoc, 'Address'); + + expect(locationType.directives.length).toBe(0); + expect(addressType.directives.length).toBe(0); + + // find the key to account for the hash + const authPolicyIdx = Object.keys(out.rootStack.Resources).find(r => r.includes('AuthRolePolicy01')); + expect(out.rootStack.Resources[authPolicyIdx]).toBeDefined; + const authRolePolicy = out.rootStack.Resources[authPolicyIdx]; + + const locationPolicy = authRolePolicy.Properties.PolicyDocument.Statement[0].Resource.filter( + r => + r['Fn::Sub'] && + r['Fn::Sub'].length && + r['Fn::Sub'].length === 2 && + r['Fn::Sub'][1].typeName && + r['Fn::Sub'][1].typeName === 'Location', + ); + expect(locationPolicy).toHaveLength(1); + + const addressPolicy = authRolePolicy.Properties.PolicyDocument.Statement[0].Resource.filter( + r => + r['Fn::Sub'] && + r['Fn::Sub'].length && + r['Fn::Sub'].length === 2 && + r['Fn::Sub'][1].typeName && + r['Fn::Sub'][1].typeName === 'Address', + ); + expect(addressPolicy).toHaveLength(1); + }); + + test(`Recursive types with diff auth modes on parent @model types`, () => { + const schema = getRecursiveSchemaWithDiffModesOnParentType(ownerAuthDirective, privateIAMDirective); + const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['AWS_IAM'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + + const tagType = getObjectType(schemaDoc, 'Tag'); + const expectedDirectiveNames = [userPoolsDirectiveName, iamDirectiveName]; + + expectMultiple(tagType, expectedDirectiveNames); + }); + + test(`Recursive types without @model`, () => { + const schema = getSchemaWithRecursiveNonModelField(ownerRestrictedIAMPrivateAuthDirective); + const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['AWS_IAM'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + + const tagType = getObjectType(schemaDoc, 'Tag'); + const expectedDirectiveNames = [userPoolsDirectiveName, iamDirectiveName]; + + expectMultiple(tagType, expectedDirectiveNames); + }); + + test(`Nested types without @model getting directives applied (cognito default, api key additional)`, () => { + const schema = getSchemaWithNonModelField(privateAndPublicDirective); + const transformer = getTransformer(withAuthModes(userPoolsDefaultConfig, ['API_KEY'])); + + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + + const locationType = getObjectType(schemaDoc, 'Location'); + const addressType = getObjectType(schemaDoc, 'Address'); + const expectedDirectiveNames = [userPoolsDirectiveName, apiKeyDirectiveName]; + + if (expectedDirectiveNames && expectedDirectiveNames.length > 0) { + let expectedDireciveNameCount = 0; + + for (const expectedDirectiveName of expectedDirectiveNames) { + expect(locationType.directives.find(d => d.name.value === expectedDirectiveName)).toBeDefined(); + expectedDireciveNameCount++; + } + + expect(expectedDireciveNameCount).toEqual(locationType.directives.length); + + expectedDireciveNameCount = 0; + + for (const expectedDirectiveName of expectedDirectiveNames) { + expect(addressType.directives.find(d => d.name.value === expectedDirectiveName)).toBeDefined(); + expectedDireciveNameCount++; + } + + expect(expectedDireciveNameCount).toEqual(addressType.directives.length); + } + }); + + test(`ModelXConnection type is getting the directives added, when a field has @hasMany but one fo the types has no queries defined`, () => { + const validSchema = ` + type User @model + @auth(rules: [ + { allow: private, provider: iam, operations: [read] } + { allow: groups, groups: ["group"], operations: [read, update, delete] }, + ]) { + id: ID! + posts: [Post!] @hasMany(indexName: "byUser", fields: ["id"]) + } + type Post @model(queries: null) + @auth(rules: [ + { allow: private, provider: iam, operations: [read] }, + { allow: groups, groups: ["group"], operations: [read, update, delete] } + ]) { + id: ID! + postUserId: ID! @index(name: "byUser") + message: String + }`; + const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + const out = transformer.transform(validSchema); + const schemaDoc = parse(out.schema); + const queryType = getObjectType(schemaDoc, 'Query'); + const mutationType = getObjectType(schemaDoc, 'Mutation'); + + expectTwo(getField(queryType, 'getUser'), ['aws_iam', 'aws_cognito_user_pools']); + expectTwo(getField(queryType, 'listUsers'), ['aws_iam', 'aws_cognito_user_pools']); + + expectNone(getField(mutationType, 'createUser')); + expectOne(getField(mutationType, 'updateUser'), 'aws_cognito_user_pools'); + expectOne(getField(mutationType, 'deleteUser'), 'aws_cognito_user_pools'); + + const userType = getObjectType(schemaDoc, 'User'); + expectTwo(userType, ['aws_iam', 'aws_cognito_user_pools']); + expectNone(getField(userType, 'posts')); + + const modelPostConnectionType = getObjectType(schemaDoc, 'ModelPostConnection'); + expect(modelPostConnectionType).toBeDefined(); + expectTwo(modelPostConnectionType, ['aws_iam', 'aws_cognito_user_pools']); + }); + + test(`ModelXConnection type is getting the directives added, when a field has @connection but one of the types has no queries defined. Many to Many`, () => { + const schema = ` + type Post @model @auth(rules: [{ allow: owner }]) { + id: ID! + title: String! + editors: [PostEditor] @hasMany(indexName: "byPost", fields: ["id"]) + } + # Create a join model and disable queries as you don't need them + # and can query through Post.editors and User.posts + type PostEditor + @model(queries: null) + @auth(rules: [{ allow: owner }]) { + id: ID! + postID: ID! @index(name: "byPost", sortKeyFields: ["editorID"]) + editorID: ID! @index(name: "byEditor", sortKeyFields: ["postID"]) + post: Post! @belongsTo(fields: ["postID"]) + editor: User! @belongsTo(fields: ["editorID"]) + } + type User @model @auth(rules: [{ allow: owner }]) { + id: ID! + username: String! + posts: [PostEditor] @hasMany(indexName: "byEditor", fields: ["id"]) + }`; + + const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS'])); + const out = transformer.transform(schema); + const schemaDoc = parse(out.schema); + + const modelPostEditorConnectionType = getObjectType(schemaDoc, 'ModelPostEditorConnection'); + expect(modelPostEditorConnectionType).toBeDefined(); + // since we have resolver level auth to deny providers the default is added here to ensure the access is granted if the default type is not applied on the parent + // therefore we just need to make sure that the access is at least granted on the schema level + expect(modelPostEditorConnectionType.directives.some(dir => dir.name.value === 'aws_cognito_user_pools')).toBe(true); + }); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/owner-auth.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/owner-auth.test.ts new file mode 100644 index 00000000000..db5c231707c --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/owner-auth.test.ts @@ -0,0 +1,230 @@ +import { parse } from 'graphql'; +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { getField, getObjectType } from './test-helpers'; +import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; + +test('auth transformer validation happy case', () => { + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const validSchema = ` + type Post @model @auth(rules: [{allow: owner}]) { + id: ID! + title: String! + createdAt: String + updatedAt: String + }`; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.rootStack.Resources[ResourceConstants.RESOURCES.GraphQLAPILogicalID].Properties.AuthenticationType).toEqual( + 'AMAZON_COGNITO_USER_POOLS', + ); +}); + +test('ownerfield with subscriptions', () => { + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const validSchema = ` + type Post @model @auth(rules: [ + {allow: owner, ownerField: "postOwner"} + ]){ + id: ID! + title: String + postOwner: String + }`; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + // expect 'postOwner' as an argument for subscription operations + expect(out.schema).toContain('onCreatePost(postOwner: String)'); + expect(out.schema).toContain('onUpdatePost(postOwner: String)'); + expect(out.schema).toContain('onDeletePost(postOwner: String)'); + + // expect logic in the resolvers to check for postOwner args as an allowed owner + expect(out.pipelineFunctions['Subscription.onCreatePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity0 = $util.defaultIfNull($ctx.args.postOwner, null) )', + ); + expect(out.pipelineFunctions['Subscription.onUpdatePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity0 = $util.defaultIfNull($ctx.args.postOwner, null) )', + ); + expect(out.pipelineFunctions['Subscription.onDeletePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity0 = $util.defaultIfNull($ctx.args.postOwner, null) )', + ); +}); + +test('multiple owner rules with subscriptions', () => { + const validSchema = ` + type Post @model + @auth(rules: [ + { allow: owner }, + { allow: owner, ownerField: "editor", operations: [read, update] } + ]) + { + id: ID! + title: String + owner: String + editor: String + }`; + + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + // expect 'owner' and 'editors' as arguments for subscription operations + expect(out.schema).toContain('onCreatePost(owner: String, editor: String)'); + expect(out.schema).toContain('onUpdatePost(owner: String, editor: String)'); + expect(out.schema).toContain('onDeletePost(owner: String, editor: String)'); + + // expect logic in the resolvers to check for owner args as an allowedOwner + expect(out.pipelineFunctions['Subscription.onCreatePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity0 = $util.defaultIfNull($ctx.args.owner, null) )', + ); + expect(out.pipelineFunctions['Subscription.onUpdatePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity0 = $util.defaultIfNull($ctx.args.owner, null) )', + ); + expect(out.pipelineFunctions['Subscription.onDeletePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity0 = $util.defaultIfNull($ctx.args.owner, null) )', + ); + + // expect logic in the resolvers to check for editor args as an allowedOwner + expect(out.pipelineFunctions['Subscription.onCreatePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity1 = $util.defaultIfNull($ctx.args.editor, null) )', + ); + expect(out.pipelineFunctions['Subscription.onUpdatePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity1 = $util.defaultIfNull($ctx.args.editor, null) )', + ); + expect(out.pipelineFunctions['Subscription.onDeletePost.auth.1.req.vtl']).toContain( + '#set( $ownerEntity1 = $util.defaultIfNull($ctx.args.editor, null) )', + ); +}); + +test('implicit owner fields get added to the type', () => { + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const validSchema = ` + type Post @model + @auth(rules: [ + {allow: owner, ownerField: "postOwner"} + { allow: owner, ownerField: "customOwner", identityClaim: "sub"} + ]) + { + id: ID! + title: String + } + `; + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + const schema = parse(out.schema); + const postType = getObjectType(schema, 'Post'); + expect(postType).toBeDefined(); + + const postOwnerField = getField(postType, 'postOwner'); + expect(postOwnerField).toBeDefined(); + expect((postOwnerField as any).type.name.value).toEqual('String'); + + const customOwner = getField(postType, 'customOwner'); + expect(customOwner).toBeDefined(); + expect((customOwner as any).type.name.value).toEqual('String'); +}); + +test('implicit owner fields from field level auth get added to the type', () => { + const validSchema = ` + type Post @model + { + id: ID + title: String + protectedField: String @auth(rules: [ + {allow: owner, ownerField: "postOwner"} + { allow: owner, ownerField: "customOwner", identityClaim: "sub"} + ]) + }`; + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + const schema = parse(out.schema); + const postType = getObjectType(schema, 'Post'); + expect(postType).toBeDefined(); + + const postOwnerField = getField(postType, 'postOwner'); + expect(postOwnerField).toBeDefined(); + expect((postOwnerField as any).type.name.value).toEqual('String'); + + const customOwner = getField(postType, 'customOwner'); + expect(customOwner).toBeDefined(); + expect((customOwner as any).type.name.value).toEqual('String'); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/searchable-auth.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/searchable-auth.test.ts new file mode 100644 index 00000000000..ee6677bcf10 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/searchable-auth.test.ts @@ -0,0 +1,93 @@ +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { SearchableModelTransformer } from '@aws-amplify/graphql-searchable-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; + +test('auth logic is enabled on owner/static rules in es request', () => { + const validSchema = ` + type Comment @model + @searchable + @auth(rules: [ + { allow: owner } + { allow: groups, groups: ["writer"]} + ]) + { + id: ID! + content: String + } + `; + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new SearchableModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + // expect response resolver to contain auth logic for owner rule + expect(out).toBeDefined(); + expect(out.pipelineFunctions['Query.searchComments.auth.1.req.vtl']).toContain( + '"terms": [$util.defaultIfNull($ctx.identity.claims.get("username"), $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), "___xamznone____"))],', + ); + // expect response resolver to contain auth logic for group rule + expect(out.pipelineFunctions['Query.searchComments.auth.1.req.vtl']).toContain( + '#set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"writer"}] )', + ); +}); + +test('auth logic is enabled for iam/apiKey auth rules', () => { + const validSchema = ` + type Post @model + @searchable + @auth(rules: [ + { allow: public, provider: apiKey } # api key is allowed + { allow: private, provider: iam } # auth roles are allowed + ]) { + id: ID! + content: String + secret: String @auth(rules: [{ allow: private, provider: iam }]) # only auth role can do crud on this + } + `; + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [ + { + authenticationType: 'API_KEY', + apiKeyConfig: { + description: 'E2E Test API Key', + apiKeyExpirationDays: 300, + }, + }, + { + authenticationType: 'AWS_IAM', + }, + ], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new SearchableModelTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + expect(out.schema).toContain('SearchablePostConnection @aws_api_key @aws_iam'); +}); diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/test-helpers.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/test-helpers.ts new file mode 100644 index 00000000000..7b92473311a --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/test-helpers.ts @@ -0,0 +1,10 @@ +import { ObjectTypeDefinitionNode, FieldDefinitionNode, DocumentNode, Kind } from 'graphql'; + +export const getObjectType = (doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined => { + return doc.definitions.find(def => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === type) as + | ObjectTypeDefinitionNode + | undefined; +}; +export const getField = (obj: ObjectTypeDefinitionNode, fieldName: string): FieldDefinitionNode | void => { + return obj.fields?.find(f => f.name.value === fieldName); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/accesscontrol/acm.ts b/packages/amplify-graphql-auth-transformer/src/accesscontrol/acm.ts new file mode 100644 index 00000000000..77166997285 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/accesscontrol/acm.ts @@ -0,0 +1,193 @@ +import assert from 'assert'; + +type ACMConfig = { + resources: string[]; + operations: string[]; +}; + +type SetRoleInput = { + role: string; + operations: Array; + resource?: string; +}; + +type ValidateInput = { + role?: string; + resource?: string; + operations?: Array; +}; + +type ResourceOperationInput = { + operations: Array; + role?: string; + resource?: string; +}; + +/** + * Creates an access control matrix + * The following vectors are used + * - Roles + * - Resources + * - Operations + */ +export class AccessControlMatrix { + private roles: Array; + private operations: Array; + private resources: Array; + private matrix: Array>>; + + constructor(config: ACMConfig) { + this.operations = config.operations; + this.resources = config.resources; + this.matrix = new Array(); + this.roles = new Array(); + } + + public setRole(input: SetRoleInput): void { + const { role, resource, operations } = input; + this.validate({ resource, operations }); + let allowedVector: Array>; + if (!this.roles.includes(role)) { + allowedVector = this.getResourceOperationMatrix({ operations, resource }); + this.roles.push(input.role); + this.matrix.push(allowedVector); + assert(this.roles.length === this.matrix.length, 'Roles are not aligned with Roles added in Matrix'); + } else { + allowedVector = this.getResourceOperationMatrix({ operations, resource, role }); + const roleIndex = this.roles.indexOf(role); + this.matrix[roleIndex] = allowedVector; + } + } + + public hasRole(role: string): boolean { + return this.roles.includes(role); + } + + public getRoles(): Array { + return this.roles; + } + + public getResources(): Readonly> { + return this.resources; + } + + public isAllowed(role: string, resource: string, operation: string): boolean { + this.validate({ role, resource, operations: [operation] }); + const roleIndex = this.roles.indexOf(role); + const resourceIndex = this.resources.indexOf(resource); + const operationIndex = this.operations.indexOf(operation); + return this.matrix[roleIndex][resourceIndex][operationIndex]; + } + + public resetAccessForResource(resource: string): void { + this.validate({ resource }); + const resourceIndex = this.resources.indexOf(resource); + for (let i = 0; i < this.roles.length; i++) { + this.matrix[i][resourceIndex] = new Array(this.operations.length).fill(false); + } + } + + /** + * Given an operation returns the roles which have access to at least one resource + * If fullAccess is true then it returns roles which have operation access on all resources + * @param operation string + * @param fullAccess boolean + * @returns array of roles + */ + public getRolesPerOperation(operation: string, fullAccess: boolean = false): Array { + this.validate({ operations: [operation] }); + const operationIndex = this.operations.indexOf(operation); + const roles = new Array(); + for (let x = 0; x < this.roles.length; x++) { + let hasOperation: boolean = false; + if (fullAccess) { + hasOperation = this.resources.every((resource, idx) => { + return this.matrix[x][idx][operationIndex]; + }); + } else { + hasOperation = this.resources.some((resource, idx) => { + return this.matrix[x][idx][operationIndex]; + }); + } + if (hasOperation) roles.push(this.roles[x]); + } + return roles; + } + + /** + * @returns a map of role and their access + * this object can then be used in console.table() + */ + public getAcmPerRole(): Map { + const acmPerRole: Map = new Map(); + for (let i = 0; i < this.matrix.length; i++) { + let tableObj: any = {}; + for (let y = 0; y < this.matrix[i].length; y++) { + tableObj[this.resources[y]] = this.matrix[i][y].reduce((prev: any, resource: boolean, index: number) => { + prev[this.operations[index]] = resource; + return prev; + }, {}); + } + acmPerRole.set(this.roles[i], tableObj); + } + return acmPerRole; + } + + /** + * helpers + */ + private validate(input: ValidateInput) { + if (input.resource && !this.resources.includes(input.resource)) { + throw Error(`Resource: ${input.resource} is not configued in the ACM`); + } + if (input.role && !this.roles.includes(input.role)) { + throw Error(`Role: ${input.role} does not exist in ACM.`); + } + if (input.operations) { + input.operations.forEach(operation => { + if (this.operations.indexOf(operation) === -1) throw Error(`Operation: ${operation} does not exist in the ACM.`); + }); + } + } + + /** + * + * if singular resource is specified the operations are only applied on the resource + * a denied array for every other resource is returned in the matrix + * @param operations + * @param resource + * @returns a 2d matrix containg the access for each resource + */ + private getResourceOperationMatrix(input: ResourceOperationInput): Array> { + const { operations, resource, role } = input; + let fieldAllowVector: boolean[][] = []; + let operationList: boolean[] = this.getOperationList(operations); + if (role && resource) { + const roleIndex = this.roles.indexOf(role); + const resourceIndex = this.resources.indexOf(resource); + fieldAllowVector = this.matrix[roleIndex]; + fieldAllowVector[resourceIndex] = operationList; + return fieldAllowVector; + } + for (let i = 0; i < this.resources.length; i++) { + if (resource) { + if (this.resources.indexOf(resource) === i) { + fieldAllowVector.push(operationList); + } else { + fieldAllowVector.push(new Array(this.operations.length).fill(false)); + } + } else { + fieldAllowVector.push(operationList); + } + } + return fieldAllowVector; + } + + private getOperationList(operations: Array): Array { + let operationList: Array = new Array(); + for (let operation of this.operations) { + operationList.push(operations.includes(operation)); + } + return operationList; + } +} diff --git a/packages/amplify-graphql-auth-transformer/src/accesscontrol/index.ts b/packages/amplify-graphql-auth-transformer/src/accesscontrol/index.ts new file mode 100644 index 00000000000..e07fbd95541 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/accesscontrol/index.ts @@ -0,0 +1 @@ +export { AccessControlMatrix } from './acm'; diff --git a/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts b/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts new file mode 100644 index 00000000000..bd49ca098cd --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts @@ -0,0 +1,948 @@ +import { + DirectiveWrapper, + TransformerContractError, + TransformerAuthBase, + InvalidDirectiveError, + MappingTemplate, + IAM_AUTH_ROLE_PARAMETER, + IAM_UNAUTH_ROLE_PARAMETER, + TransformerResolver, +} from '@aws-amplify/graphql-transformer-core'; +import { + DataSourceProvider, + MutationFieldType, + QueryFieldType, + TransformerTransformSchemaStepContextProvider, + TransformerContextProvider, + TransformerResolverProvider, + TransformerSchemaVisitStepContextProvider, + TransformerAuthProvider, + TransformerBeforeStepContextProvider, +} from '@aws-amplify/graphql-transformer-interfaces'; +import { + AuthRule, + authDirectiveDefinition, + ConfiguredAuthProviders, + getConfiguredAuthProviders, + AuthTransformerConfig, + collectFieldNames, + DEFAULT_GROUP_CLAIM, + MODEL_OPERATIONS, + ModelOperation, + ensureAuthRuleDefaults, + DEFAULT_IDENTITY_CLAIM, + DEFAULT_GROUPS_FIELD, + DEFAULT_OWNER_FIELD, + getModelConfig, + validateFieldRules, + validateRules, + AuthProvider, + AUTH_PROVIDER_DIRECTIVE_MAP, + extendTypeWithDirectives, + RoleDefinition, + addDirectivesToOperation, + createPolicyDocumentForManagedPolicy, + getQueryFieldNames, + getMutationFieldNames, + addSubscriptionArguments, + fieldIsList, + getSubscriptionFieldNames, + addDirectivesToField, + getSearchableConfig, + getStackForField, + NONE_DS, +} from './utils'; +import { + DirectiveNode, + FieldDefinitionNode, + ObjectTypeDefinitionNode, + InterfaceTypeDefinitionNode, + Kind, + TypeDefinitionNode, +} from 'graphql'; +import { SubscriptionLevel, ModelDirectiveConfiguration } from '@aws-amplify/graphql-model-transformer'; +import { AccessControlMatrix } from './accesscontrol'; +import { getBaseType, makeDirective, makeField, makeNamedType, ResourceConstants } from 'graphql-transformer-common'; +import * as iam from '@aws-cdk/aws-iam'; +import * as cdk from '@aws-cdk/core'; +import { + generateAuthExpressionForCreate, + generateAuthExpressionForUpdate, + generateAuthRequestExpression, + geneateAuthExpressionForDelete, + generateAuthExpressionForField, + generateFieldAuthResponse, + generateAuthExpressionForQueries, + generateAuthExpressionForSubscriptions, +} from './resolvers'; +import { toUpper } from 'graphql-transformer-common'; + +// @ auth +// changing the schema +// - transformSchema +// adding resolver +// - generateResolver +// editing IAM policy +// - generateResolver (cdk) +// resolver mapping + +// resolver.ts for auth pipeline slots + +export class AuthTransformer extends TransformerAuthBase implements TransformerAuthProvider { + private config: AuthTransformerConfig; + private configuredAuthProviders: ConfiguredAuthProviders; + // access control + private roleMap: Map; + private authModelConfig: Map; + private authNonModelConfig: Map; + // model config + private modelDirectiveConfig: Map; + // schema generation + private seenNonModelTypes: Map>; + // iam policy generation + private generateIAMPolicyforUnauthRole: boolean; + private generateIAMPolicyforAuthRole: boolean; + private authPolicyResources = new Set(); + private unauthPolicyResources = new Set(); + + constructor(config: AuthTransformerConfig) { + super('amplify-auth-transformer', authDirectiveDefinition); + this.config = config; + this.modelDirectiveConfig = new Map(); + this.seenNonModelTypes = new Map(); + this.authModelConfig = new Map(); + this.roleMap = new Map(); + this.generateIAMPolicyforUnauthRole = false; + this.generateIAMPolicyforAuthRole = false; + this.authNonModelConfig = new Map(); + } + + before = (context: TransformerBeforeStepContextProvider): void => { + // if there was no auth config in the props we add the authConfig from the context + this.config.authConfig = this.config.authConfig || context.authConfig; + this.configuredAuthProviders = getConfiguredAuthProviders(this.config); + }; + + object = (def: ObjectTypeDefinitionNode, directive: DirectiveNode, context: TransformerSchemaVisitStepContextProvider): void => { + const modelDirective = def.directives?.find(dir => dir.name.value === 'model'); + if (!modelDirective) { + throw new TransformerContractError('Types annotated with @auth must also be annotated with @model.'); + } + const typeName = def.name.value; + const authDir = new DirectiveWrapper(directive); + const rules: AuthRule[] = authDir.getArguments<{ rules: Array }>({ rules: [] }).rules; + ensureAuthRuleDefaults(rules); + // validate rules + validateRules(rules, this.configuredAuthProviders); + // create access control for object + const acm = new AccessControlMatrix({ + operations: MODEL_OPERATIONS, + resources: collectFieldNames(def), + }); + // Check the rules to see if we should generate Auth/Unauth Policies + this.setAuthPolicyFlag(rules); + this.setUnauthPolicyFlag(rules); + // add object into policy + this.addTypeToResourceReferences(def.name.value, rules); + // turn rules into roles and add into acm and roleMap + this.convertRulesToRoles(acm, rules); + this.modelDirectiveConfig.set(typeName, getModelConfig(modelDirective, typeName, context.isProjectUsingDataStore())); + this.authModelConfig.set(typeName, acm); + }; + + field = ( + parent: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, + field: FieldDefinitionNode, + directive: DirectiveNode, + context: TransformerSchemaVisitStepContextProvider, + ): void => { + if (parent.kind === Kind.INTERFACE_TYPE_DEFINITION) { + throw new InvalidDirectiveError( + `The @auth directive cannot be placed on an interface's field. See ${parent.name.value}${field.name.value}`, + ); + } + const isParentTypeBuiltinType = + parent.name.value === context.output.getQueryTypeName() || + parent.name.value === context.output.getMutationTypeName() || + parent.name.value === context.output.getSubscriptionTypeName(); + + if (isParentTypeBuiltinType) { + console.warn( + `Be careful when using @auth directives on a field in a root type. @auth directives on field definitions use the source \ +object to perform authorization logic and the source will be an empty object for fields on root types. \ +Static group authorization should perform as expected.`, + ); + } + // context.api.host.resolver + // context.resolver -> resolver manager -> dynamodb, relation directives, searchable + // creates field resolver + + const modelDirective = parent.directives?.find(dir => dir.name.value === 'model'); + const typeName = parent.name.value; + const fieldName = field.name.value; + const authDir = new DirectiveWrapper(directive); + const rules: AuthRule[] = authDir.getArguments<{ rules: Array }>({ rules: [] }).rules; + ensureAuthRuleDefaults(rules); + validateFieldRules(rules, isParentTypeBuiltinType, modelDirective !== undefined, this.configuredAuthProviders); + + // regardless if a model directive is used we generate the policy for iam auth + this.setAuthPolicyFlag(rules); + this.setUnauthPolicyFlag(rules); + this.addFieldToResourceReferences(parent.name.value, field.name.value, rules); + + if (modelDirective) { + // auth on models + let acm: AccessControlMatrix; + // check if the parent is already in the model config if not add it + if (!this.modelDirectiveConfig.has(typeName)) { + this.modelDirectiveConfig.set(typeName, getModelConfig(modelDirective, typeName, context.isProjectUsingDataStore())); + acm = new AccessControlMatrix({ + operations: MODEL_OPERATIONS, + resources: collectFieldNames(parent), + }); + } else { + acm = this.authModelConfig.get(typeName) as AccessControlMatrix; + acm.resetAccessForResource(fieldName); + } + this.convertRulesToRoles(acm, rules, fieldName); + this.authModelConfig.set(typeName, acm); + } else { + // if @auth is used without @model only generate static group rules in the resolver + // since we only protect the field for non models we store the typeName + fieldName + // in the authNonModelTypes map + const staticRules = rules.filter((rule: AuthRule) => rule.allow !== 'owner' && !rule.groupsField); + const typeFieldName = `${typeName}:${fieldName}`; + const acm = new AccessControlMatrix({ + operations: ['read'], + resources: [typeFieldName], + }); + this.convertRulesToRoles(acm, staticRules, typeFieldName, ['read']); + this.authNonModelConfig.set(typeFieldName, acm); + } + }; + + transformSchema = (context: TransformerTransformSchemaStepContextProvider): void => { + const getOwnerFields = (acm: AccessControlMatrix) => { + return acm.getRoles().reduce((prev: string[], role: string) => { + if (this.roleMap.get(role)!.strategy === 'owner') prev.push(this.roleMap.get(role)!.entity!); + return prev; + }, []); + }; + for (let [modelName, acm] of this.authModelConfig) { + const def = context.output.getObject(modelName)!; + // collect ownerFields and them in the model + this.addFieldsToObject(context, modelName, getOwnerFields(acm)); + // Get the directives we need to add to the GraphQL nodes + const providers = this.getAuthProviders(acm.getRoles()); + const directives = this.getServiceDirectives(providers, providers.length === 0 ? this.shouldAddDefaultServiceDirective() : false); + if (directives.length > 0) { + extendTypeWithDirectives(context, modelName, directives); + } + this.protectSchemaOperations(context, def, acm); + this.propagateAuthDirectivesToNestedTypes(context, context.output.getObject(modelName)!, providers); + } + for (let [typeFieldName, acm] of this.authNonModelConfig) { + // protect the non model field + const [typeName, fieldName] = typeFieldName.split(':'); + const providers = this.getAuthProviders(acm.getRoles()); + const directives = this.getServiceDirectives(providers, false); + if (directives.length > 0) { + addDirectivesToField(context, typeName, fieldName, directives); + } + } + }; + + generateResolvers = (context: TransformerContextProvider): void => { + // generate iam policies + this.generateIAMPolicies(context); + // generate auth resolver code + for (let [modelName, acm] of this.authModelConfig) { + const indexKeyName = `${modelName}:indicies`; + const def = context.output.getObject(modelName)!; + const searchableDirective = def.directives.find(dir => dir.name.value === 'searchable'); + // queries + const queryFields = getQueryFieldNames(this.modelDirectiveConfig.get(modelName)!); + for (let query of queryFields.values()) { + switch (query.type) { + case QueryFieldType.GET: + this.protectGetResolver(context, def, query.typeName, query.fieldName, acm); + break; + case QueryFieldType.LIST: + this.protectListResolver(context, def, query.typeName, query.fieldName, acm); + break; + case QueryFieldType.SYNC: + this.protectSyncResolver(context, def, query.typeName, query.fieldName, acm); + break; + default: + throw new TransformerContractError('Unkown query field type'); + } + } + // protect additional query fields if they exist + if (context.metadata.has(indexKeyName)) { + for (let index of context.metadata.get>(indexKeyName)!.values()) { + this.protectListResolver(context, def, def.name.value, index, acm); + } + } + // check if searchable if included in the typeName + if (searchableDirective) { + // protect search query + const config = getSearchableConfig(searchableDirective, modelName); + this.protectSearchResolver(context, def, context.output.getQueryTypeName()!, config.queries.search, acm); + } + // get fields specified in the schema + // if there is a role that does not have read access on the field then we create a field resolver + const readRoles = acm.getRolesPerOperation('read'); + const modelFields = def.fields?.filter(f => acm.getResources().includes(f.name.value)) ?? []; + for (let field of modelFields) { + const allowedRoles = readRoles.filter(r => acm.isAllowed(r, field.name.value, 'read')); + if (allowedRoles.length < readRoles.length) { + if (field.type.kind === Kind.NON_NULL_TYPE) { + throw new InvalidDirectiveError(`\nPer-field auth on the required field ${field.name.value} is not supported with subscriptions. + Either make the field optional, set auth on the object and not the field, or disable subscriptions for the object (setting level to off or public)\n`); + } + this.protectFieldResolver(context, def, modelName, field.name.value, allowedRoles); + } + } + const mutationFields = getMutationFieldNames(this.modelDirectiveConfig.get(modelName)!); + for (let mutation of mutationFields.values()) { + switch (mutation.type) { + case MutationFieldType.CREATE: + this.protectCreateResolver(context, def, mutation.typeName, mutation.fieldName, acm); + break; + case MutationFieldType.UPDATE: + this.protectUpdateResolver(context, def, mutation.typeName, mutation.fieldName, acm); + break; + case MutationFieldType.DELETE: + this.protectDeleteResolver(context, def, mutation.typeName, mutation.fieldName, acm); + break; + default: + throw new TransformerContractError('Unkown Mutation field type'); + } + } + + const subscriptionFieldNames = getSubscriptionFieldNames(this.modelDirectiveConfig.get(modelName)!); + const subscriptionRoles = acm + .getRolesPerOperation('read') + .map(role => this.roleMap.get(role)!) + // for subscriptions we only use static rules or owner rule where the field is not a list + .filter(roleDef => (roleDef.strategy === 'owner' && !fieldIsList(def.fields ?? [], roleDef.entity!)) || roleDef.static); + for (let subscription of subscriptionFieldNames) { + this.protectSubscriptionResolver(context, subscription.typeName, subscription.fieldName, subscriptionRoles); + } + } + + for (let [typeFieldName, acm] of this.authNonModelConfig) { + // field resolvers + const [typeName, fieldName] = typeFieldName.split(':'); + const def = context.output.getObject(typeName); + this.protectFieldResolver(context, def, typeName, fieldName, acm.getRoles()); + } + }; + + protectSchemaOperations = ( + ctx: TransformerTransformSchemaStepContextProvider, + def: ObjectTypeDefinitionNode, + acm: AccessControlMatrix, + ): void => { + const modelConfig = this.modelDirectiveConfig.get(def.name.value)!; + const indexKeyName = `${def.name.value}:indicies`; + const searchableDirective = def.directives.find(dir => dir.name.value === 'searchable'); + const addServiceDirective = (typeName: string, operation: ModelOperation, operationName: string | null = null) => { + if (operationName) { + const includeDefault = this.doesTypeHaveRulesForOperation(acm, operation); + const providers = this.getAuthProviders(acm.getRolesPerOperation(operation, operation === 'delete')); + const operationDirectives = this.getServiceDirectives(providers, includeDefault); + if (operationDirectives.length > 0) { + addDirectivesToOperation(ctx, typeName, operationName, operationDirectives); + } + this.addOperationToResourceReferences(typeName, operationName, acm.getRoles()); + } + }; + // default model operations TODO: protect sync queries once supported + addServiceDirective(ctx.output.getQueryTypeName()!, 'read', modelConfig?.queries?.get); + addServiceDirective(ctx.output.getQueryTypeName()!, 'read', modelConfig?.queries?.list); + addServiceDirective(ctx.output.getMutationTypeName()!, 'create', modelConfig?.mutations?.create); + addServiceDirective(ctx.output.getMutationTypeName()!, 'update', modelConfig?.mutations?.update); + addServiceDirective(ctx.output.getMutationTypeName()!, 'delete', modelConfig?.mutations?.delete); + // @index queries + if (ctx.metadata.has(indexKeyName)) { + for (let index of ctx.metadata.get>(indexKeyName)!.values()) { + addServiceDirective(ctx.output.getQueryTypeName(), 'read', index); + } + } + // @searchable + if (searchableDirective) { + const config = getSearchableConfig(searchableDirective, def.name.value); + addServiceDirective(ctx.output.getQueryTypeName(), 'read', config.queries.search); + } + + const subscriptions = modelConfig?.subscriptions; + if (subscriptions.level === SubscriptionLevel.on) { + const subscriptionArguments = acm + .getRolesPerOperation('read') + .map(role => this.roleMap.get(role)!) + .filter(roleDef => roleDef.strategy === 'owner' && !fieldIsList(def.fields ?? [], roleDef.entity!)); + if (subscriptions.onCreate && modelConfig?.mutations?.create) { + for (let onCreateSub of subscriptions.onCreate) { + addServiceDirective(ctx.output.getSubscriptionTypeName()!, 'read', onCreateSub); + addSubscriptionArguments(ctx, onCreateSub, subscriptionArguments); + } + } + if (subscriptions.onUpdate && modelConfig?.mutations?.update) { + for (let onUpdateSub of subscriptions.onUpdate) { + addServiceDirective(ctx.output.getSubscriptionTypeName()!, 'read', onUpdateSub); + addSubscriptionArguments(ctx, onUpdateSub, subscriptionArguments); + } + } + if (subscriptions.onDelete && modelConfig?.mutations?.delete) { + for (let onDeleteSub of subscriptions.onDelete) { + addServiceDirective(ctx.output.getSubscriptionTypeName()!, 'read', onDeleteSub); + addSubscriptionArguments(ctx, onDeleteSub, subscriptionArguments); + } + } + } + }; + + protectGetResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const roleDefinitions = acm.getRolesPerOperation('read').map(r => this.roleMap.get(r)!); + const authExpression = generateAuthExpressionForQueries(this.configuredAuthProviders, roleDefinitions, def.fields ?? []); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + }; + protectListResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const roleDefinitions = acm.getRolesPerOperation('read').map(r => this.roleMap.get(r)!); + const authExpression = generateAuthExpressionForQueries(this.configuredAuthProviders, roleDefinitions, def.fields ?? []); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + }; + protectSyncResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + if (ctx.isProjectUsingDataStore()) { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const roleDefinitions = acm.getRolesPerOperation('read').map(r => this.roleMap.get(r)!); + const authExpression = generateAuthExpressionForQueries(this.configuredAuthProviders, roleDefinitions, def.fields ?? []); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + } + }; + protectSearchResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const roleDefinitions = acm.getRolesPerOperation('read').map(r => this.roleMap.get(r)!); + const authExpression = generateAuthExpressionForQueries(this.configuredAuthProviders, roleDefinitions, def.fields ?? [], 'opensearch'); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + }; + /* + Field Resovler can protect the following + - model fields + - relational fields (hasOne, hasMany, belongsTo) + - fields on an operation (query/mutation) + - protection on predictions/function/no directive + Order of precendence + - resolver in api host (ex. @function, @predictions) + - resolver in resolver manager (ex. @hasOne, @hasMany @belongsTo) + - no resolver creates a blank non-pipeline resolver will return the source field + */ + protectFieldResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + roles: Array, + ): void => { + const roleDefinitions = roles.map(r => this.roleMap.get(r)!); + const hasModelDirective = def.directives.some(dir => dir.name.value === 'model'); + const stack = getStackForField(ctx, def, fieldName, hasModelDirective); + if (ctx.api.host.hasResolver(typeName, fieldName)) { + // TODO: move pipeline resolvers created in the api host to the resolver manager + const fieldResolver = ctx.api.host.getResolver(typeName, fieldName) as any; + const fieldAuthExpression = generateAuthExpressionForField(this.configuredAuthProviders, roleDefinitions, []); + if (!ctx.api.host.hasDataSource(NONE_DS)) { + ctx.api.host.addNoneDataSource(NONE_DS); + } + const authFunction = ctx.api.host.addAppSyncFunction( + `${toUpper(typeName)}${toUpper(fieldName)}AuthFN`, + MappingTemplate.s3MappingTemplateFromString(fieldAuthExpression, `${typeName}.${fieldName}.auth.req.vtl`), + MappingTemplate.inlineTemplateFromString('$util.toJson({})'), + NONE_DS, + stack, + ); + (fieldResolver.pipelineConfig.functions as string[]).unshift(authFunction.functionId); + } else if (ctx.resolvers.hasResolver(typeName, fieldName)) { + // if there a resolver in the resolver manager we can append to the auth slot + const fieldResolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const authExpression = generateAuthExpressionForQueries(this.configuredAuthProviders, roleDefinitions, def.fields ?? []); + fieldResolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + } else { + const fieldAuthExpression = generateAuthExpressionForField(this.configuredAuthProviders, roleDefinitions, def.fields ?? []); + const subsEnabled = hasModelDirective ? this.modelDirectiveConfig.get(typeName)!.subscriptions.level === 'on' : false; + const fieldResponse = generateFieldAuthResponse('Mutation', fieldName, subsEnabled); + const resolver = ctx.resolvers.addResolver( + typeName, + fieldName, + new TransformerResolver( + typeName, + fieldName, + MappingTemplate.s3MappingTemplateFromString(fieldAuthExpression, `${typeName}.${fieldName}.req.vtl`), + MappingTemplate.s3MappingTemplateFromString(fieldResponse, `${typeName}.${fieldName}.res.vtl`), + ['init'], + ['finish'], + ), + ); + resolver.mapToStack(stack); + } + }; + protectCreateResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const fields = acm.getResources(); + const createRoles = acm.getRolesPerOperation('create').map(role => { + const allowedFields = fields.filter(resource => acm.isAllowed(role, resource, 'create')); + const roleDefinition = this.roleMap.get(role)!; + roleDefinition.allowedFields = allowedFields.length === fields.length ? [] : allowedFields; + return roleDefinition; + }); + const authExpression = generateAuthExpressionForCreate(this.configuredAuthProviders, createRoles, def.fields ?? []); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + }; + protectUpdateResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const fields = acm.getResources(); + const updateDeleteRoles = [...new Set([...acm.getRolesPerOperation('update'), ...acm.getRolesPerOperation('delete')])]; + // protect fields to be updated and fields that can't be set to null (partial delete on fields) + const totalRoles = updateDeleteRoles.map(role => { + const allowedFields = fields.filter(resource => acm.isAllowed(role, resource, 'update')); + const nullAllowedFileds = fields.filter(resource => acm.isAllowed(role, resource, 'delete')); + const roleDefinition = this.roleMap.get(role)!; + roleDefinition.allowedFields = allowedFields.length === fields.length ? [] : allowedFields; + roleDefinition.nullAllowedFields = nullAllowedFileds.length === fields.length ? [] : nullAllowedFileds; + return roleDefinition; + }); + const datasource = ctx.api.host.getDataSource(`${def.name.value}Table`) as DataSourceProvider; + const requestExpression = generateAuthRequestExpression(); + const authExpression = generateAuthExpressionForUpdate(this.configuredAuthProviders, totalRoles, def.fields ?? []); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(requestExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.res.vtl`), + datasource, + ); + }; + + protectDeleteResolver = ( + ctx: TransformerContextProvider, + def: ObjectTypeDefinitionNode, + typeName: string, + fieldName: string, + acm: AccessControlMatrix, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + // only roles with full delete on every field can delete + const deleteRoles = acm.getRolesPerOperation('delete', true).map(role => this.roleMap.get(role)!); + const datasource = ctx.api.host.getDataSource(`${def.name.value}Table`) as DataSourceProvider; + const requestExpression = generateAuthRequestExpression(); + const authExpression = geneateAuthExpressionForDelete(this.configuredAuthProviders, deleteRoles, def.fields ?? []); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(requestExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.res.vtl`), + datasource, + ); + }; + + protectSubscriptionResolver = ( + ctx: TransformerContextProvider, + typeName: string, + fieldName: string, + subscriptionRoles: Array, + ): void => { + const resolver = ctx.resolvers.getResolver(typeName, fieldName) as TransformerResolverProvider; + const authExpression = generateAuthExpressionForSubscriptions(this.configuredAuthProviders, subscriptionRoles); + resolver.addToSlot( + 'auth', + MappingTemplate.s3MappingTemplateFromString(authExpression, `${typeName}.${fieldName}.{slotName}.{slotIndex}.req.vtl`), + ); + }; + + /* + Role Helpers + */ + private convertRulesToRoles(acm: AccessControlMatrix, authRules: AuthRule[], field?: string, overideOperations?: ModelOperation[]) { + for (let rule of authRules) { + let operations: ModelOperation[] = overideOperations ? overideOperations : rule.operations || MODEL_OPERATIONS; + if (rule.groups && !rule.groupsField) { + rule.groups.forEach(group => { + const groupClaim = rule.groupClaim || DEFAULT_GROUP_CLAIM; + const roleName = `${rule.provider}:staticGroup:${group}:${groupClaim}`; + if (!(roleName in this.roleMap)) { + this.roleMap.set(roleName, { + provider: rule.provider!, + strategy: rule.allow, + static: true, + claim: groupClaim, + entity: group, + }); + } + acm.setRole({ role: roleName, resource: field, operations }); + }); + } else { + let roleName: string; + let roleDefinition: RoleDefinition; + switch (rule.provider) { + case 'apiKey': + roleName = 'apiKey:public'; + roleDefinition = { provider: rule.provider, strategy: rule.allow, static: true }; + break; + case 'iam': + roleName = `iam:${rule.allow}`; + roleDefinition = { + provider: rule.provider, + strategy: rule.allow, + static: true, + claim: rule.allow === 'private' ? 'authRole' : 'unauthRole', + }; + break; + case 'oidc': + case 'userPools': + if (rule.allow === 'groups') { + const groupClaim = rule.groupClaim || DEFAULT_GROUP_CLAIM; + const groupsField = rule.groupsField || DEFAULT_GROUPS_FIELD; + roleName = `${rule.provider}:dynamicGroup:${groupsField}:${groupClaim}`; + roleDefinition = { + provider: rule.provider, + strategy: rule.allow, + static: false, + claim: groupClaim, + entity: groupsField, + }; + } else if (rule.allow === 'owner') { + const ownerField = rule.ownerField || DEFAULT_OWNER_FIELD; + const ownerClaim = rule.identityClaim || DEFAULT_IDENTITY_CLAIM; + roleName = `${rule.provider}:owner:${ownerField}:${ownerClaim}`; + roleDefinition = { + provider: rule.provider, + strategy: rule.allow, + static: false, + claim: ownerClaim, + entity: ownerField, + }; + } else if (rule.allow === 'private') { + roleName = `${rule.provider}:${rule.allow}`; + roleDefinition = { + provider: rule.provider, + strategy: rule.allow, + static: true, + }; + } else { + throw new TransformerContractError(`Could not create a role from ${JSON.stringify(rule)}`); + } + break; + default: + throw new TransformerContractError(`Could not create a role from ${JSON.stringify(rule)}`); + } + if (!(roleName in this.roleMap)) { + this.roleMap.set(roleName, roleDefinition); + } + acm.setRole({ role: roleName, resource: field, operations }); + } + } + } + + private doesTypeHaveRulesForOperation(acm: AccessControlMatrix, operation: ModelOperation) { + const rolesHasDefaultProvider = (roles: Array) => { + return roles.some(r => this.roleMap.get(r)!.provider! === this.configuredAuthProviders.default); + }; + const roles = acm.getRolesPerOperation(operation, operation === 'delete'); + return rolesHasDefaultProvider(roles) || (roles.length === 0 && this.shouldAddDefaultServiceDirective()); + } + private getAuthProviders(roles: Array): Array { + const providers: Set = new Set(); + // get the roles created for type + for (let role of roles) { + providers.add(this.roleMap.get(role)!.provider); + } + if (this.configuredAuthProviders.hasAdminUIEnabled) { + providers.add('iam'); + } + return Array.from(providers); + } + + /* + Schema Generation Helpers + */ + private addFieldsToObject(ctx: TransformerTransformSchemaStepContextProvider, modelName: string, ownerFields: Array) { + const modelObject = ctx.output.getObject(modelName)!; + const existingFields = collectFieldNames(modelObject); + const ownerFieldsToAdd = ownerFields.filter(field => !existingFields.includes(field)); + for (let ownerField of ownerFieldsToAdd) { + (modelObject as any).fields.push(makeField(ownerField, [], makeNamedType('String'))); + } + ctx.output.putType(modelObject); + } + private propagateAuthDirectivesToNestedTypes( + ctx: TransformerTransformSchemaStepContextProvider, + def: ObjectTypeDefinitionNode, + providers: Array, + ) { + const nonModelTypePredicate = (fieldType: TypeDefinitionNode): TypeDefinitionNode | undefined => { + if (fieldType) { + if (fieldType.kind !== 'ObjectTypeDefinition') { + return undefined; + } + const typeModel = fieldType.directives!.find(dir => dir.name.value === 'model'); + return typeModel !== undefined ? undefined : fieldType; + } + return fieldType; + }; + const nonModelFieldTypes = def + .fields!.map(f => ctx.output.getType(getBaseType(f.type)) as TypeDefinitionNode) + .filter(nonModelTypePredicate); + for (const nonModelFieldType of nonModelFieldTypes) { + const nonModelName = nonModelFieldType.name.value; + const hasSeenType = this.seenNonModelTypes.has(nonModelFieldType.name.value); + let directives = this.getServiceDirectives(providers, hasSeenType); + if (!hasSeenType) { + this.seenNonModelTypes.set(nonModelName, new Set([...directives.map(dir => dir.name.value)])); + // since we haven't seen this type before we add it to the iam policy resource sets + const hasIAM = directives.some(dir => dir.name.value === 'aws_iam') || this.configuredAuthProviders.default === 'iam'; + if (hasIAM) { + this.unauthPolicyResources.add(`${nonModelFieldType.name.value}/null`); + this.authPolicyResources.add(`${nonModelFieldType.name.value}/null`); + } + } else { + const currentDirectives = this.seenNonModelTypes.get(nonModelName)!; + directives = directives.filter(dir => !currentDirectives.has(dir.name.value)); + this.seenNonModelTypes.set(nonModelName, new Set([...directives.map(dir => dir.name.value), ...currentDirectives])); + } + // we continue to check the nested types if we find that directives list is not empty or if haven't seen the type before + if (directives.length > 0 || !hasSeenType) { + extendTypeWithDirectives(ctx, nonModelFieldType.name.value, directives); + this.propagateAuthDirectivesToNestedTypes(ctx, nonModelFieldType, providers); + } + } + } + + private getServiceDirectives(providers: Readonly>, addDefaultIfNeeded: boolean = true): Array { + if (providers.length === 0) { + return []; + } + const directives: Array = new Array(); + /* + We only add a service directive if it's not the default or + it's the default but there are other rules under different providers. + For fields we don't we don't add the default since it would open up access. + */ + const addDirectiveIfNeeded = (provider: AuthProvider, directiveName: string): void => { + if ( + (this.configuredAuthProviders.default !== provider && providers.some(p => p === provider)) || + (this.configuredAuthProviders.default === provider && providers.some(p => p !== provider && addDefaultIfNeeded === true)) + ) { + directives.push(makeDirective(directiveName, [])); + } + }; + + for (let [authProvider, directiveName] of AUTH_PROVIDER_DIRECTIVE_MAP) { + addDirectiveIfNeeded(authProvider, directiveName); + } + /* + If we have any rules for the default provider AND those with other providers, + we add the default provider directive, regardless of the addDefaultDirective value + + For example if we have this rule and the default is API_KEY + @auth(rules: [{ allow: owner }, { allow: public, operations: [read] }]) + + Then we need to add @aws_api_key on the queries along with @aws_cognito_user_pools, but we + cannot add @aws_api_key to other operations since their is no rule granted access to it + */ + if ( + providers.some(p => p === this.configuredAuthProviders.default) && + providers.some(p => p !== this.configuredAuthProviders.default) && + !directives.some(d => d.name.value === AUTH_PROVIDER_DIRECTIVE_MAP.get(this.configuredAuthProviders.default)) + ) { + directives.push(makeDirective(AUTH_PROVIDER_DIRECTIVE_MAP.get(this.configuredAuthProviders.default) as string, [])); + } + return directives; + } + /** + * When AdminUI is enabled, all the types and operations get IAM auth. If the default auth mode is + * not IAM all the fields will need to have the default auth mode directive to ensure both IAM and deault + * auth modes are allowed to access + * default auth provider needs to be added if AdminUI is enabled and default auth type is not IAM + * @returns boolean + */ + private shouldAddDefaultServiceDirective(): boolean { + return this.configuredAuthProviders.hasAdminUIEnabled && this.config.authConfig.defaultAuthentication.authenticationType !== 'AWS_IAM'; + } + /* + IAM Helpers + */ + private generateIAMPolicies(ctx: TransformerContextProvider) { + // iam + if (this.generateIAMPolicyforAuthRole) { + // Sanity check to make sure we're not generating invalid policies, where no resources are defined. + if (this.authPolicyResources.size === 0) { + // When AdminUI is enabled, IAM auth is added but it does not need any policies to be generated + if (!this.configuredAuthProviders.hasAdminUIEnabled) { + throw new TransformerContractError('AuthRole policies should be generated, but no resources were added.'); + } + } else { + const authRoleParameter = (ctx.stackManager.getParameter(IAM_AUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString; + const authPolicyDocuments = createPolicyDocumentForManagedPolicy(this.authPolicyResources); + const rootStack = ctx.stackManager.rootStack; + for (let i = 0; i < authPolicyDocuments.length; i++) { + const paddedIndex = `${i + 1}`.padStart(2, '0'); + const resourceName = `${ResourceConstants.RESOURCES.AuthRolePolicy}${paddedIndex}`; + new iam.ManagedPolicy(rootStack, resourceName, { + document: iam.PolicyDocument.fromJson(authPolicyDocuments[i]), + // we need to add the arn path as this is something cdk is looking for when using imported roles in policies + roles: [ + iam.Role.fromRoleArn( + rootStack, + 'auth-role-name', + `arn:aws:iam::${cdk.Stack.of(rootStack).account}:role/${authRoleParameter}`, + ), + ], + }); + } + } + } + if (this.generateIAMPolicyforUnauthRole) { + // Sanity check to make sure we're not generating invalid policies, where no resources are defined. + if (this.unauthPolicyResources.size === 0) { + throw new TransformerContractError('UnauthRole policies should be generated, but no resources were added'); + } + const unauthRoleParameter = (ctx.stackManager.getParameter(IAM_UNAUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString; + const unauthPolicyDocuments = createPolicyDocumentForManagedPolicy(this.unauthPolicyResources); + const rootStack = ctx.stackManager.rootStack; + for (let i = 0; i < unauthPolicyDocuments.length; i++) { + const paddedIndex = `${i + 1}`.padStart(2, '0'); + const resourceName = `${ResourceConstants.RESOURCES.UnauthRolePolicy}${paddedIndex}`; + new iam.ManagedPolicy(ctx.stackManager.rootStack, resourceName, { + document: iam.PolicyDocument.fromJson(unauthPolicyDocuments[i]), + roles: [ + iam.Role.fromRoleArn( + rootStack, + 'unauth-role-name', + `arn:aws:iam::${cdk.Stack.of(rootStack).account}:role/${unauthRoleParameter}`, + ), + ], + }); + } + } + } + private setAuthPolicyFlag(rules: AuthRule[]): void { + if (rules.length === 0 || this.generateIAMPolicyforAuthRole === true) { + return; + } + for (const rule of rules) { + if ((rule.allow === 'private' || rule.allow === 'public') && rule.provider === 'iam') { + this.generateIAMPolicyforAuthRole = true; + return; + } + } + } + + private setUnauthPolicyFlag(rules: AuthRule[]): void { + if (rules.length === 0 || this.generateIAMPolicyforUnauthRole === true) { + return; + } + for (const rule of rules) { + if (rule.allow === 'public' && rule.provider === 'iam') { + this.generateIAMPolicyforUnauthRole = true; + return; + } + } + } + + private addOperationToResourceReferences(operationName: string, fieldName: string, roles: Array) { + const iamPublicRolesExist = roles.some(r => this.roleMap.get(r)!.provider === 'iam' && this.roleMap.get(r)!.strategy === 'public'); + const iamPrivateRolesExist = roles.some(r => this.roleMap.get(r)!.provider === 'iam' && this.roleMap.get(r)!.strategy === 'private'); + + if (iamPublicRolesExist) { + this.unauthPolicyResources.add(`${operationName}/${fieldName}`); + this.authPolicyResources.add(`${operationName}/${fieldName}`); + } + if (iamPrivateRolesExist) { + this.authPolicyResources.add(`${operationName}/${fieldName}`); + } + } + + /** + * TODO: Change Resource Ref Object/Field Functions to work with roles + */ + private addTypeToResourceReferences(typeName: string, rules: AuthRule[]): void { + const iamPublicRulesExist = rules.some(r => r.allow === 'public' && r.provider === 'iam' && r.generateIAMPolicy); + const iamPrivateRulesExist = rules.some(r => r.allow === 'private' && r.provider === 'iam' && r.generateIAMPolicy); + + if (iamPublicRulesExist) { + this.unauthPolicyResources.add(`${typeName}/null`); + this.authPolicyResources.add(`${typeName}/null`); + } + if (iamPrivateRulesExist) { + this.authPolicyResources.add(`${typeName}/null`); + } + } + + private addFieldToResourceReferences(typeName: string, fieldName: string, rules: AuthRule[]): void { + const iamPublicRulesExist = rules.some(r => r.allow === 'public' && r.provider === 'iam' && r.generateIAMPolicy); + const iamPrivateRulesExist = rules.some(r => r.allow === 'private' && r.provider === 'iam' && r.generateIAMPolicy); + + if (iamPublicRulesExist) { + this.unauthPolicyResources.add(`${typeName}/${fieldName}`); + this.authPolicyResources.add(`${typeName}/${fieldName}`); + } + if (iamPrivateRulesExist) { + this.authPolicyResources.add(`${typeName}/${fieldName}`); + } + } +} diff --git a/packages/amplify-graphql-auth-transformer/src/index.ts b/packages/amplify-graphql-auth-transformer/src/index.ts new file mode 100644 index 00000000000..5382eacf29f --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/index.ts @@ -0,0 +1,4 @@ +export * from './graphql-auth-transformer'; +export * from './utils/constants'; +export * from './utils/definitions'; +export { AccessControlMatrix } from './accesscontrol'; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/field.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/field.ts new file mode 100644 index 00000000000..e5ec9ffe460 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/field.ts @@ -0,0 +1,136 @@ +import { OPERATION_KEY } from '@aws-amplify/graphql-model-transformer'; +import { FieldDefinitionNode } from 'graphql'; +import { + Expression, + iff, + not, + ref, + equals, + str, + compoundExpression, + printBlock, + toJson, + set, + methodCall, + nul, + ifElse, + bool, + raw, + forEach, +} from 'graphql-mapping-template'; +import { + RoleDefinition, + splitRoles, + COGNITO_AUTH_TYPE, + OIDC_AUTH_TYPE, + ConfiguredAuthProviders, + fieldIsList, + IS_AUTHORIZED_FLAG, +} from '../utils'; +import { getOwnerClaim, generateStaticRoleExpression, apiKeyExpression, iamExpression, emptyPayload } from './helpers'; + +// Field Read VTL Functions +const generateDynamicAuthReadExpression = (roles: Array, fields: ReadonlyArray) => { + const ownerExpressions = new Array(); + const dynamicGroupExpressions = new Array(); + roles.forEach((role, idx) => { + const entityIsList = fieldIsList(fields, role.entity!); + if (role.strategy === 'owner') { + ownerExpressions.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref(`ownerEntity${idx}`), methodCall(ref('util.defaultIfNull'), ref(`ctx.source.${role.entity!}`), nul())), + set(ref(`ownerClaim${idx}`), getOwnerClaim(role.claim!)), + ...(entityIsList + ? [ + forEach(ref('allowedOwner'), ref(`ownerEntity${idx}`), [ + iff( + equals(ref('allowedOwner'), ref(`ownerClaim${idx}`)), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw('#break')]), + ), + ]), + ] + : [iff(equals(ref(`ownerEntity${idx}`), ref(`ownerClaim${idx}`)), set(ref(IS_AUTHORIZED_FLAG), bool(true)))]), + ]), + ), + ); + } + if (role.strategy === 'groups') { + dynamicGroupExpressions.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref(`groupEntity${idx}`), methodCall(ref('util.defaultIfNull'), ref(`ctx.source.${role.entity!}`), nul())), + set(ref(`groupClaim${idx}`), getOwnerClaim(role.claim!)), + forEach(ref('userGroup'), ref('dynamicGroupClaim'), [ + iff( + entityIsList + ? methodCall(ref(`groupEntity${idx}.contains`), ref('userGroup')) + : equals(ref(`groupEntity${idx}`), ref('userGroup')), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw('#break')]), + ), + ]), + ]), + ), + ); + } + }); + return [...(ownerExpressions.length > 0 || dynamicGroupExpressions.length > 0 ? [...ownerExpressions, ...dynamicGroupExpressions] : [])]; +}; + +export const generateAuthExpressionForField = ( + provider: ConfiguredAuthProviders, + roles: Array, + fields: ReadonlyArray, +): string => { + const { cogntoStaticRoles, cognitoDynamicRoles, oidcStaticRoles, oidcDynamicRoles, iamRoles, apiKeyRoles } = splitRoles(roles); + const totalAuthExpressions: Array = [set(ref(IS_AUTHORIZED_FLAG), bool(false))]; + if (provider.hasApiKey) { + totalAuthExpressions.push(apiKeyExpression(apiKeyRoles)); + } + if (provider.hasIAM) { + totalAuthExpressions.push(iamExpression(iamRoles, provider.hasAdminUIEnabled, provider.adminUserPoolID)); + } + if (provider.hasUserPools) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(COGNITO_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(cogntoStaticRoles), + ...generateDynamicAuthReadExpression(cognitoDynamicRoles, fields), + ]), + ), + ); + } + if (provider.hasOIDC) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(OIDC_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(oidcStaticRoles), + ...generateDynamicAuthReadExpression(oidcDynamicRoles, fields), + ]), + ), + ); + } + totalAuthExpressions.push(iff(not(ref(IS_AUTHORIZED_FLAG)), ref('util.unauthorized()'))); + return printBlock('Field Authorization Steps')(compoundExpression([...totalAuthExpressions, emptyPayload])); +}; + +/** + * This is the response resolver for fields to protect subscriptions + * @param subscriptionsEnabled + * @returns + */ +export const generateFieldAuthResponse = (operation: string, fieldName: string, subscriptionsEnabled: boolean): string => { + if (subscriptionsEnabled) { + return printBlock('Checking for allowed operations which can return this field')( + compoundExpression([ + set(ref('operation'), methodCall(ref('util.defaultIfNull'), methodCall(ref('ctx.source.get'), str(OPERATION_KEY)), nul())), + ifElse(equals(ref('operation'), str(operation)), toJson(nul()), toJson(ref(`context.source.${fieldName}`))), + ]), + ); + } + return printBlock('Return Source Field')(toJson(ref(`context.source.${fieldName}`))); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/helpers.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/helpers.ts new file mode 100644 index 00000000000..5ac4e417b94 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/helpers.ts @@ -0,0 +1,152 @@ +import { + qref, + Expression, + ifElse, + iff, + methodCall, + not, + ref, + set, + str, + raw, + obj, + bool, + compoundExpression, + printBlock, + toJson, + forEach, + list, + equals, + or, +} from 'graphql-mapping-template'; +import { NONE_VALUE } from 'graphql-transformer-common'; +import { + DEFAULT_COGNITO_IDENTITY_CLAIM, + RoleDefinition, + IS_AUTHORIZED_FLAG, + ALLOWED_FIELDS, + API_KEY_AUTH_TYPE, + ADMIN_ROLE, + IAM_AUTH_TYPE, + MANAGE_ROLE, +} from '../utils'; + +// note in the resolver that operation is protected by auth +export const setHasAuthExpression: Expression = qref(methodCall(ref('ctx.stash.put'), str('hasAuth'), bool(true))); + +// since the keySet returns a set we can convert it to a list by converting to json and parsing back as a list +export const getInputFields = (): Expression => { + return set(ref('inputFields'), methodCall(ref('util.parseJson'), methodCall(ref('util.toJson'), ref('ctx.args.input.keySet()')))); +}; + +export const getIdentityClaimExp = (value: Expression, defaultValueExp: Expression): Expression => { + return methodCall(ref('util.defaultIfNull'), methodCall(ref('ctx.identity.claims.get'), value), defaultValueExp); +}; + +// for create mutations and subscriptions +export const addAllowedFieldsIfElse = (fieldKey: string, breakLoop: boolean = false): Expression => { + return ifElse( + not(ref(`${fieldKey}.isEmpty()`)), + qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), ref(fieldKey))), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), ...(breakLoop ? [raw('#break')] : [])]), + ); +}; + +// iam check +export const iamCheck = (claim: string, exp: Expression) => iff(equals(ref('ctx.identity.userArn'), ref(`ctx.stash.${claim}`)), exp); + +/** + * Behavior of auth v1 + * Order of how the owner value is retrieved from the jwt + * if claim is username + * 1. username + * 2. cognito:username + * 3. none value + * + * if claim is custom + * 1. custom + * 2. none value + */ +export const getOwnerClaim = (ownerClaim: string): Expression => { + if (ownerClaim === 'username') { + return getIdentityClaimExp(str(ownerClaim), getIdentityClaimExp(str(DEFAULT_COGNITO_IDENTITY_CLAIM), str(NONE_VALUE))); + } + return getIdentityClaimExp(str(ownerClaim), str(NONE_VALUE)); +}; + +export const responseCheckForErrors = () => + iff(ref('ctx.error'), methodCall(ref('util.error'), ref('ctx.error.message'), ref('ctx.error.type'))); + +// Common Expressions + +export const generateStaticRoleExpression = (roles: Array): Array => { + const staticRoleExpression: Array = new Array(); + const privateRoleIdx = roles.findIndex(r => r.strategy === 'private'); + if (privateRoleIdx > -1) { + staticRoleExpression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + roles.splice(privateRoleIdx, 1); + } + if (roles.length > 0) { + staticRoleExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref('staticGroupRoles'), raw(JSON.stringify(roles.map(r => ({ claim: r.claim, entity: r.entity }))))), + forEach(ref('groupRole'), ref('staticGroupRoles'), [ + set(ref('groupsInToken'), getIdentityClaimExp(ref('groupRole.claim'), list([]))), + iff( + methodCall(ref('groupsInToken.contains'), ref('groupRole.entity')), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw(`#break`)]), + ), + ]), + ]), + ), + ); + } + return staticRoleExpression; +}; + +export const apiKeyExpression = (roles: Array) => + iff( + equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), + compoundExpression([...(roles.length > 0 ? [set(ref(IS_AUTHORIZED_FLAG), bool(true))] : [])]), + ); + +export const iamExpression = (roles: Array, adminuiEnabled: boolean = false, adminUserPoolID?: string) => { + const expression = new Array(); + // allow if using admin ui + if (adminuiEnabled) { + expression.push( + iff( + or([ + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID}${ADMIN_ROLE}`)), + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID}${MANAGE_ROLE}`)), + ]), + raw('#return($util.toJson({})'), + ), + ); + } + if (roles.length > 0) { + for (let role of roles) { + expression.push(iff(not(ref(IS_AUTHORIZED_FLAG)), iamCheck(role.claim!, set(ref(IS_AUTHORIZED_FLAG), bool(true))))); + } + } + return iff(equals(ref('util.authType()'), str(IAM_AUTH_TYPE)), compoundExpression(expression)); +}; + +// Get Request for Update and Delete +export const generateAuthRequestExpression = () => { + const statements = [ + set(ref('GetRequest'), obj({ version: str('2018-05-29'), operation: str('GetItem') })), + ifElse( + ref('ctx.stash.metadata.modelObjectKey'), + set(ref('key'), ref('ctx.stash.metadata.modelObjectKey')), + compoundExpression([set(ref('key'), obj({ id: methodCall(ref('util.dynamodb.toDynamoDB'), ref('ctx.args.input.id')) }))]), + ), + qref(methodCall(ref('GetRequest.put'), str('key'), ref('key'))), + toJson(ref('GetRequest')), + ]; + return printBlock('Get Request template')(compoundExpression(statements)); +}; + +export const emptyPayload = toJson(raw(JSON.stringify({ version: '2018-05-29', payload: {} }))); diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/index.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/index.ts new file mode 100644 index 00000000000..5f9e8476d39 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/index.ts @@ -0,0 +1,7 @@ +export { generateAuthExpressionForQueries } from './query'; +export { generateAuthExpressionForCreate } from './mutation.create'; +export { generateAuthExpressionForUpdate } from './mutation.update'; +export { geneateAuthExpressionForDelete } from './mutation.delete'; +export { generateAuthExpressionForField, generateFieldAuthResponse } from './field'; +export { generateAuthExpressionForSubscriptions } from './subscriptions'; +export { generateAuthRequestExpression } from './helpers'; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.create.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.create.ts new file mode 100644 index 00000000000..22dd6a95d22 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.create.ts @@ -0,0 +1,274 @@ +import { FieldDefinitionNode } from 'graphql'; +import { + Expression, + compoundExpression, + set, + ref, + bool, + raw, + iff, + and, + isNullOrEmpty, + not, + methodCall, + qref, + list, + nul, + forEach, + equals, + str, + or, + printBlock, +} from 'graphql-mapping-template'; +import { + getOwnerClaim, + getIdentityClaimExp, + getInputFields, + addAllowedFieldsIfElse, + emptyPayload, + setHasAuthExpression, + iamCheck, +} from './helpers'; +import { + ADMIN_ROLE, + API_KEY_AUTH_TYPE, + COGNITO_AUTH_TYPE, + ConfiguredAuthProviders, + IAM_AUTH_TYPE, + MANAGE_ROLE, + OIDC_AUTH_TYPE, + RoleDefinition, + splitRoles, + fieldIsList, + IS_AUTHORIZED_FLAG, + ALLOWED_FIELDS, + DENIED_FIELDS, +} from '../utils'; + +/** + * There is only one role for ApiKey we can use the first index + * @param roles + * @returns Expression | null + */ +const apiKeyExpression = (roles: Array) => { + const expression = new Array(); + if (roles.length === 0) { + return iff(equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), ref('util.unauthorized()')); + } + if (roles[0].allowedFields!.length > 0) { + expression.push(set(ref(`${ALLOWED_FIELDS}`), raw(JSON.stringify(roles[0].allowedFields)))); + } else { + expression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + return iff(equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), compoundExpression(expression)); +}; + +/** + * No need to combine allowed fields as the request can only be signed by one iam role + * @param roles + * @returns + */ +const iamExpression = (roles: Array, hasAdminUIEnabled: boolean = false, adminUserPoolID?: string) => { + const expression = new Array(); + // allow if using admin ui + if (hasAdminUIEnabled) { + expression.push( + iff( + or([ + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID!}${ADMIN_ROLE}`)), + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID!}${MANAGE_ROLE}`)), + ]), + raw('#return($util.toJson({})'), + ), + ); + } + if (roles.length > 0) { + for (let role of roles) { + if (role.allowedFields!.length > 0) { + expression.push( + iamCheck(role.claim!, compoundExpression([set(ref(`${ALLOWED_FIELDS}`), raw(JSON.stringify(role.allowedFields)))])), + ); + } else { + expression.push(iamCheck(role.claim!, set(ref(IS_AUTHORIZED_FLAG), bool(true)))); + } + } + } else { + expression.push(ref('util.unauthorized()')); + } + return iff(equals(ref('util.authType()'), str(IAM_AUTH_TYPE)), compoundExpression(expression)); +}; + +const generateStaticRoleExpression = (roles: Array): Array => { + const staticRoleExpression: Array = new Array(); + const privateRoleIdx = roles.findIndex(r => r.strategy === 'private'); + if (privateRoleIdx > -1) { + const privateRole = roles[privateRoleIdx]; + if (privateRole.allowedFields!.length > 0) { + staticRoleExpression.push(qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), raw(JSON.stringify(privateRole.allowedFields))))); + } else { + staticRoleExpression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + roles.splice(privateRoleIdx, 1); + } + if (roles.length > 0) { + staticRoleExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref('staticGroupRoles'), + raw(JSON.stringify(roles.map(r => ({ claim: r.claim, entity: r.entity, allowedFields: r.allowedFields ?? [] })))), + ), + forEach(/** for */ ref('groupRole'), /** in */ ref('staticGroupRoles'), [ + set(ref('groupsInToken'), getIdentityClaimExp(ref('groupRole.claim'), list([]))), + iff( + methodCall(ref('groupsInToken.contains'), ref('groupRole.entity')), + addAllowedFieldsIfElse('groupRole.allowedFields', true), + ), + ]), + ]), + ), + ); + } + return staticRoleExpression; +}; + +const dynamicGroupRoleExpression = (roles: Array, fields: ReadonlyArray): Array => { + const ownerExpression = new Array(); + const dynamicGroupExpression = new Array(); + roles.forEach((role, idx) => { + const entityIsList = fieldIsList(fields, role.entity!); + if (role.strategy === 'owner') { + ownerExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref(`ownerEntity${idx}`), + methodCall(ref('util.defaultIfNull'), ref(`ctx.args.input.${role.entity!}`), entityIsList ? list([]) : nul()), + ), + set(ref(`ownerClaim${idx}`), getOwnerClaim(role.claim!)), + set(ref(`ownerAllowedFields${idx}`), raw(JSON.stringify(role.allowedFields))), + ...(entityIsList + ? [ + forEach(ref('allowedOwner'), ref(`ownerEntity${idx}`), [ + iff(equals(ref('allowedOwner'), ref(`ownerClaim${idx}`)), addAllowedFieldsIfElse(`ownerAllowedFields${idx}`, true)), + ]), + ] + : [iff(equals(ref(`ownerClaim${idx}`), ref(`ownerEntity${idx}`)), addAllowedFieldsIfElse(`ownerAllowedFields${idx}`))]), + iff( + and([isNullOrEmpty(ref(`ownerEntity${idx}`)), not(methodCall(ref('ctx.args.input.containsKey'), str(role.entity!)))]), + compoundExpression([ + qref( + methodCall( + ref('ctx.args.input.put'), + str(role.entity!), + entityIsList ? list([ref(`ownerClaim${idx}`)]) : ref(`ownerClaim${idx}`), + ), + ), + addAllowedFieldsIfElse(`ownerAllowedFields${idx}`), + ]), + ), + ]), + ), + ); + } + if (role.strategy === 'groups') { + dynamicGroupExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref(`groupEntity${idx}`), + methodCall(ref('util.defaultIfNull'), ref(`ctx.args.input.${role.entity!}`), entityIsList ? list([]) : nul()), + ), + set(ref(`groupClaim${idx}`), getIdentityClaimExp(str(role.claim!), list([]))), + set(ref(`groupAllowedFields${idx}`), raw(JSON.stringify(role.allowedFields))), + forEach(ref('userGroup'), ref(`groupClaim${idx}`), [ + iff( + entityIsList + ? methodCall(ref(`groupEntity${idx}.contains`), ref('userGroup')) + : equals(ref(`groupEntity${idx}`), ref('userGroup')), + addAllowedFieldsIfElse(`groupAllowedFields${idx}`, true), + ), + ]), + ]), + ), + ); + } + }); + + return [...(ownerExpression.length > 0 ? ownerExpression : []), ...(dynamicGroupExpression.length > 0 ? dynamicGroupExpression : [])]; +}; + +/** + * Unauthorized if + * - auth conditions could not be met + * - there are fields conditions that could not be met + * @param providers + * @param roles + * @param fields + * @returns + */ +export const generateAuthExpressionForCreate = ( + providers: ConfiguredAuthProviders, + roles: Array, + fields: ReadonlyArray, +): string => { + const { + cogntoStaticRoles: cognitoStaticGroupRoles, + cognitoDynamicRoles, + oidcStaticRoles: oidcStaticGroupRoles, + oidcDynamicRoles, + apiKeyRoles, + iamRoles, + } = splitRoles(roles); + const totalAuthExpressions: Array = [ + setHasAuthExpression, + getInputFields(), + set(ref(IS_AUTHORIZED_FLAG), bool(false)), + set(ref(ALLOWED_FIELDS), list([])), + ]; + if (providers.hasApiKey) { + totalAuthExpressions.push(apiKeyExpression(apiKeyRoles)); + } + if (providers.hasIAM) { + totalAuthExpressions.push(iamExpression(iamRoles, providers.hasAdminUIEnabled, providers.adminUserPoolID)); + } + if (providers.hasUserPools) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(COGNITO_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(cognitoStaticGroupRoles), + ...dynamicGroupRoleExpression(cognitoDynamicRoles, fields), + ]), + ), + ); + } + if (providers.hasOIDC) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(OIDC_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(oidcStaticGroupRoles), + ...dynamicGroupRoleExpression(oidcDynamicRoles, fields), + ]), + ), + ); + } + totalAuthExpressions.push( + iff(and([not(ref(IS_AUTHORIZED_FLAG)), ref(`${ALLOWED_FIELDS}.isEmpty()`)]), ref('util.unauthorized()')), + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref(DENIED_FIELDS), methodCall(ref('util.list.copyAndRemoveAll'), ref('inputFields'), ref(ALLOWED_FIELDS))), + iff( + ref(`${DENIED_FIELDS}.size() > 0`), + methodCall(ref('util.error'), str(`Unauthorized on \${${DENIED_FIELDS}}`), str('Unauthorized')), + ), + ]), + ), + ); + return printBlock('Authorization Steps')(compoundExpression([...totalAuthExpressions, emptyPayload])); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.delete.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.delete.ts new file mode 100644 index 00000000000..c5656f061dc --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.delete.ts @@ -0,0 +1,189 @@ +import { FieldDefinitionNode } from 'graphql'; +import { + Expression, + printBlock, + compoundExpression, + bool, + equals, + iff, + raw, + ref, + set, + str, + methodCall, + or, + forEach, + list, + not, + nul, +} from 'graphql-mapping-template'; +import { emptyPayload, getIdentityClaimExp, getOwnerClaim, iamCheck, setHasAuthExpression } from './helpers'; +import { + ADMIN_ROLE, + API_KEY_AUTH_TYPE, + COGNITO_AUTH_TYPE, + ConfiguredAuthProviders, + fieldIsList, + IAM_AUTH_TYPE, + IS_AUTHORIZED_FLAG, + MANAGE_ROLE, + OIDC_AUTH_TYPE, + RoleDefinition, + splitRoles, +} from '../utils'; + +/** + * There is only one role for ApiKey we can use the first index + * @param roles + * @returns Expression | null + */ +const apiKeyExpression = (roles: Array) => { + const expression = new Array(); + if (roles.length === 0) { + return iff(equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), ref('util.unauthorized()')); + } + if (roles.length > 0) { + expression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + return iff(equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), compoundExpression(expression)); +}; +/** + * No need to combine allowed fields as the request can only be signed by one iam role + * @param roles + * @returns + */ +const iamExpression = (roles: Array, hasAdminUIEnabled: boolean = false, adminUserPoolID?: string) => { + const expression = new Array(); + // allow if using admin ui + if (hasAdminUIEnabled) { + expression.push( + iff( + or([ + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID}${ADMIN_ROLE}`)), + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID}${MANAGE_ROLE}`)), + ]), + raw('#return($util.toJson({})'), + ), + ); + } + if (roles.length > 0) { + for (let role of roles) { + iamCheck(role.claim!, set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + } else { + expression.push(ref('util.unauthorized()')); + } + return iff(equals(ref('util.authType()'), str(IAM_AUTH_TYPE)), compoundExpression(expression)); +}; + +const generateStaticRoleExpression = (roles: Array): Array => { + const staticRoleExpression: Array = new Array(); + const privateRoleIdx = roles.findIndex(r => r.strategy === 'private'); + if (privateRoleIdx > -1) { + staticRoleExpression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + roles.splice(privateRoleIdx, -1); + } + if (roles.length > 0) { + staticRoleExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref('staticGroupRoles'), raw(JSON.stringify(roles.map(r => ({ claim: r.claim, entity: r.entity }))))), + forEach(/** for */ ref('groupRole'), /** in */ ref('staticGroupRoles'), [ + set(ref('groupsInToken'), getIdentityClaimExp(ref('groupRole.claim'), list([]))), + iff( + methodCall(ref('groupsInToken.contains'), ref('groupRole.entity')), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw('#break')]), + ), + ]), + ]), + ), + ); + } + return staticRoleExpression; +}; + +const dynamicGroupRoleExpression = (roles: Array, fields: ReadonlyArray) => { + const ownerExpression = new Array(); + const dynamicGroupExpression = new Array(); + roles.forEach((role, idx) => { + const entityIsList = fieldIsList(fields, role.entity!); + if (role.strategy === 'owner') { + ownerExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref(`ownerEntity${idx}`), methodCall(ref('util.defaultIfNull'), ref(`ctx.result.${role.entity!}`), nul())), + set(ref(`ownerClaim${idx}`), getOwnerClaim(role.claim!)), + ...(entityIsList + ? [ + forEach(ref('allowedOwner'), ref(`ownerEntity${idx}`), [ + iff(equals(ref('allowedOwner'), ref(`ownerClaim${idx}`)), set(ref(IS_AUTHORIZED_FLAG), bool(true))), + ]), + ] + : [iff(equals(ref(`ownerEntity${idx}`), ref(`ownerClaim${idx}`)), set(ref(IS_AUTHORIZED_FLAG), bool(true)))]), + ]), + ), + ); + } + if (role.strategy === 'groups') { + dynamicGroupExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref(`groupEntity${idx}`), + methodCall(ref('util.defaultIfNull'), ref(`ctx.result.${role.entity}`), entityIsList ? list([]) : nul()), + ), + set(ref(`groupClaim${idx}`), getIdentityClaimExp(str(role.claim!), list([]))), + forEach(ref('userGroup'), ref(`groupClaim${idx}`), [ + iff( + entityIsList + ? methodCall(ref(`groupEntity${idx}.contains`), ref('userGroup')) + : equals(ref(`groupEntity${idx}`), ref('userGroup')), + set(ref(IS_AUTHORIZED_FLAG), bool(true)), + ), + ]), + ]), + ), + ); + } + }); + return [...(ownerExpression.length > 0 ? ownerExpression : []), ...(dynamicGroupExpression.length > 0 ? dynamicGroupExpression : [])]; +}; + +export const geneateAuthExpressionForDelete = ( + providers: ConfiguredAuthProviders, + roles: Array, + fields: ReadonlyArray, +) => { + const { cogntoStaticRoles, cognitoDynamicRoles, oidcStaticRoles, oidcDynamicRoles, apiKeyRoles, iamRoles } = splitRoles(roles); + const totalAuthExpressions: Array = [setHasAuthExpression, set(ref(IS_AUTHORIZED_FLAG), bool(false))]; + if (providers.hasApiKey) { + totalAuthExpressions.push(apiKeyExpression(apiKeyRoles)); + } + if (providers.hasIAM) { + totalAuthExpressions.push(iamExpression(iamRoles, providers.hasAdminUIEnabled, providers.adminUserPoolID)); + } + if (providers.hasUserPools) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(COGNITO_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(cogntoStaticRoles), + ...dynamicGroupRoleExpression(cognitoDynamicRoles, fields), + ]), + ), + ); + } + if (providers.hasOIDC) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(OIDC_AUTH_TYPE)), + compoundExpression([...generateStaticRoleExpression(oidcStaticRoles), ...dynamicGroupRoleExpression(oidcDynamicRoles, fields)]), + ), + ); + } + totalAuthExpressions.push(iff(not(ref(IS_AUTHORIZED_FLAG)), ref('util.unauthorized()'))); + return printBlock('Authorization Steps')(compoundExpression([...totalAuthExpressions, emptyPayload])); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.update.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.update.ts new file mode 100644 index 00000000000..a58101a3ce3 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/mutation.update.ts @@ -0,0 +1,318 @@ +import { FieldDefinitionNode } from 'graphql'; +import { + compoundExpression, + iff, + raw, + set, + ref, + forEach, + bool, + Expression, + not, + obj, + list, + qref, + equals, + str, + and, + methodCall, + toJson, + printBlock, + ifElse, + nul, + or, +} from 'graphql-mapping-template'; +import { + ADMIN_ROLE, + API_KEY_AUTH_TYPE, + COGNITO_AUTH_TYPE, + ConfiguredAuthProviders, + IAM_AUTH_TYPE, + MANAGE_ROLE, + OIDC_AUTH_TYPE, + RoleDefinition, + splitRoles, + fieldIsList, + IS_AUTHORIZED_FLAG, + ALLOWED_FIELDS, + NULL_ALLOWED_FIELDS, + DENIED_FIELDS, +} from '../utils'; +import { getIdentityClaimExp, responseCheckForErrors, getOwnerClaim, getInputFields, setHasAuthExpression, iamCheck } from './helpers'; + +/** + * There is only one role for ApiKey we can use the first index + * @param roles + * @returns Expression | null + */ +const apiKeyExpression = (roles: Array) => { + const expression = new Array(); + if (roles.length === 0) { + return iff(equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), ref('util.unauthorized()')); + } + if (roles[0].allowedFields!.length > 0 || roles[0].nullAllowedFields!.length > 0) { + expression.push( + set(ref(`${ALLOWED_FIELDS}`), raw(JSON.stringify(roles[0].allowedFields))), + set(ref(`${NULL_ALLOWED_FIELDS}`), raw(JSON.stringify(roles[0].nullAllowedFields))), + ); + } else { + expression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + return iff(equals(ref('util.authType()'), str(API_KEY_AUTH_TYPE)), compoundExpression(expression)); +}; + +const iamExpression = (roles: Array, hasAdminUIEnabled: boolean = false, adminUserPoolID?: string) => { + const expression = new Array(); + // allow if using admin ui + if (hasAdminUIEnabled) { + expression.push( + iff( + or([ + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID}${ADMIN_ROLE}`)), + methodCall(ref('ctx.identity.userArn.contains'), str(`${adminUserPoolID}${MANAGE_ROLE}`)), + ]), + raw('#return($util.toJson({})'), + ), + ); + } + if (roles.length > 0) { + for (let role of roles) { + if (role.allowedFields!.length > 0 || role.nullAllowedFields!.length > 0) { + expression.push( + iamCheck( + role.claim!, + compoundExpression([ + set(ref(`${ALLOWED_FIELDS}`), raw(JSON.stringify(role.allowedFields))), + set(ref(`${NULL_ALLOWED_FIELDS}`), raw(JSON.stringify(role.nullAllowedFields))), + ]), + ), + ); + } else { + iamCheck(role.claim!, set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + } + } else { + expression.push(ref('util.unauthorized()')); + } + return iff(equals(ref('util.authType()'), str(IAM_AUTH_TYPE)), compoundExpression(expression)); +}; + +const generateStaticRoleExpression = (roles: Array) => { + const staticRoleExpression: Array = new Array(); + const privateRoleIdx = roles.findIndex(r => r.strategy === 'private'); + if (privateRoleIdx > -1) { + const privateRole = roles[privateRoleIdx]; + if (privateRole.allowedFields!.length > 0 || privateRole.nullAllowedFields!.length > 0) { + staticRoleExpression.push( + qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), raw(JSON.stringify(privateRole.allowedFields)))), + qref(methodCall(ref(`${NULL_ALLOWED_FIELDS}.addAll`), raw(JSON.stringify(privateRole.nullAllowedFields)))), + ); + } else { + staticRoleExpression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + } + roles.splice(privateRoleIdx, 1); + } + if (roles.length > 0) { + staticRoleExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref('staticGroupRoles'), + raw( + JSON.stringify( + roles.map(r => ({ + claim: r.claim, + entity: r.entity, + allowedFields: r.allowedFields, + nullAllowedFields: r.nullAllowedFields, + })), + ), + ), + ), + forEach(/** for */ ref('groupRole'), /** in */ ref('staticGroupRoles'), [ + set(ref('groupsInToken'), getIdentityClaimExp(ref('groupRole.claim'), list([]))), + iff( + methodCall(ref('groupsInToken.contains'), ref('groupRole.entity')), + compoundExpression([ + // if we find that it's not fully allowed on update (update/delete) we add the field conditions + // otherwise we set to true and break + ifElse( + or([not(ref(`groupRole.allowedFields.isEmpty()`)), not(ref('groupRole.nullAllowedFields.isEmpty()'))]), + compoundExpression([ + qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), ref('groupRole.allowedFields'))), + qref(methodCall(ref(`${NULL_ALLOWED_FIELDS}.addAll`), ref('groupRole.nullAllowedFields'))), + ]), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw('#break')]), + ), + ]), + ), + ]), + ]), + ), + ); + } + return staticRoleExpression; +}; +const dynamicGroupRoleExpression = (roles: Array, fields: ReadonlyArray): Array => { + const ownerExpression = new Array(); + const dynamicGroupExpression = new Array(); + roles.forEach((role, idx) => { + const entityIsList = fieldIsList(fields, role.entity!); + if (role.strategy === 'owner') { + ownerExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref(`ownerEntity${idx}`), + methodCall(ref('util.defaultIfNull'), ref(`ctx.result.${role.entity!}`), entityIsList ? list([]) : nul()), + ), + set(ref(`ownerClaim${idx}`), getOwnerClaim(role.claim!)), + set(ref(`ownerAllowedFields${idx}`), raw(JSON.stringify(role.allowedFields))), + set(ref(`ownerNullAllowedFields${idx}`), raw(JSON.stringify(role.nullAllowedFields))), + ...(entityIsList + ? [ + forEach(ref('allowedOwner'), ref(`ownerEntity${idx}`), [ + iff( + equals(ref('allowedOwner'), ref(`ownerClaim${idx}`)), + ifElse( + or([not(ref(`ownerAllowedFields${idx}.isEmpty()`)), not(ref(`ownerNullAllowedFields${idx}.isEmpty()`))]), + compoundExpression([ + qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), ref(`ownerAllowedFields${idx}`))), + qref(methodCall(ref(`${NULL_ALLOWED_FIELDS}.addAll`), ref(`ownerNullAllowedFields${idx}`))), + ]), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw('#break')]), + ), + ), + ]), + ] + : [ + iff( + equals(ref(`ownerEntity${idx}`), ref(`ownerClaim${idx}`)), + ifElse( + or([not(ref(`ownerAllowedFields${idx}.isEmpty()`)), not(ref(`ownerNullAllowedFields${idx}.isEmpty()`))]), + compoundExpression([ + qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), ref(`ownerAllowedFields${idx}`))), + qref(methodCall(ref(`${NULL_ALLOWED_FIELDS}.addAll`), ref(`ownerNullAllowedFields${idx}`))), + ]), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true))]), + ), + ), + ]), + ]), + ), + ); + } + if (role.strategy === 'groups') { + dynamicGroupExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set( + ref(`groupEntity${idx}`), + methodCall(ref('util.defaultIfNull'), ref(`ctx.result.${role.entity}`), entityIsList ? list([]) : nul()), + ), + set(ref(`groupClaim${idx}`), getIdentityClaimExp(str(role.claim!), list([]))), + set(ref(`groupAllowedFields${idx}`), raw(JSON.stringify(role.allowedFields))), + set(ref(`groupNullAllowedFields${idx}`), raw(JSON.stringify(role.nullAllowedFields))), + forEach(ref('userGroup'), ref(`groupClaim${idx}`), [ + iff( + entityIsList + ? methodCall(ref(`groupEntity${idx}.contains`), ref('userGroup')) + : equals(ref(`groupEntity${idx}`), ref('userGroup')), + ifElse( + or([not(ref(`groupAllowedFields${idx}.isEmpty()`)), not(ref(`groupNullAllowedFields${idx}.isEmpty()`))]), + compoundExpression([ + qref(methodCall(ref(`${ALLOWED_FIELDS}.addAll`), ref('groupRole.allowedFields'))), + qref(methodCall(ref(`${NULL_ALLOWED_FIELDS}.addAll`), ref('groupRole.nullAllowedFields'))), + ]), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw('#break')]), + ), + ), + ]), + ]), + ), + ); + } + }); + return [...(ownerExpression.length > 0 ? ownerExpression : []), ...(dynamicGroupExpression.length > 0 ? dynamicGroupExpression : [])]; +}; + +/** + * For update we need to check for allowed fields and null allowed fields + * unauthorized if + * - none of the roles have been met and there are no field conditions + * - role is partially allowed but the field conditions have not been met + * @param providers + * @param roles + * @param fields + * @returns + */ +export const generateAuthExpressionForUpdate = ( + providers: ConfiguredAuthProviders, + roles: Array, + fields: ReadonlyArray, +) => { + const { cogntoStaticRoles, cognitoDynamicRoles, oidcStaticRoles, oidcDynamicRoles, apiKeyRoles, iamRoles } = splitRoles(roles); + const totalAuthExpressions: Array = [ + setHasAuthExpression, + responseCheckForErrors(), + getInputFields(), + set(ref(IS_AUTHORIZED_FLAG), bool(false)), + set(ref(`${ALLOWED_FIELDS}`), list([])), + set(ref(`${NULL_ALLOWED_FIELDS}`), list([])), + set(ref(`${DENIED_FIELDS}`), obj({})), + ]; + if (providers.hasApiKey) { + totalAuthExpressions.push(apiKeyExpression(apiKeyRoles)); + } + if (providers.hasIAM) { + totalAuthExpressions.push(iamExpression(iamRoles, providers.hasAdminUIEnabled, providers.adminUserPoolID)); + } + if (providers.hasUserPools) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(COGNITO_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(cogntoStaticRoles), + ...dynamicGroupRoleExpression(cognitoDynamicRoles, fields), + ]), + ), + ); + } + if (providers.hasOIDC) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(OIDC_AUTH_TYPE)), + compoundExpression([...generateStaticRoleExpression(oidcStaticRoles), ...dynamicGroupRoleExpression(oidcDynamicRoles, fields)]), + ), + ); + } + totalAuthExpressions.push( + iff( + and([not(ref(IS_AUTHORIZED_FLAG)), ref(`${ALLOWED_FIELDS}.isEmpty()`), ref(`${NULL_ALLOWED_FIELDS}.isEmpty()`)]), + ref('util.unauthorized()'), + ), + // if not authorized we check the field conditions + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + forEach(ref('entry'), ref('util.map.copyAndRetainAllKeys($ctx.args.input, $inputFields).entrySet()'), [ + iff( + and([methodCall(ref('util.isNull'), ref('entry.value')), not(ref(`${NULL_ALLOWED_FIELDS}.contains($entry.value)`))]), + qref(methodCall(ref(`${DENIED_FIELDS}.put`), ref('entry.key'), str(''))), + ), + ]), + forEach(ref('deniedField'), ref(`util.list.copyAndRemoveAll($inputFields, \$${ALLOWED_FIELDS})`), [ + qref(methodCall(ref(`${DENIED_FIELDS}.put`), ref('deniedField'), str(''))), + ]), + ]), + ), + iff( + ref(`${DENIED_FIELDS}.keySet().size() > 0`), + methodCall(ref('util.error'), str(`Unauthorized on \${${DENIED_FIELDS}.keySet()}`), str('Unauthorized')), + ), + ); + return printBlock('Authorization Steps')(compoundExpression([...totalAuthExpressions, toJson(obj({}))])); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/query.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/query.ts new file mode 100644 index 00000000000..fc244d65912 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/query.ts @@ -0,0 +1,204 @@ +import { FieldDefinitionNode } from 'graphql'; +import { + compoundExpression, + Expression, + obj, + printBlock, + and, + equals, + iff, + methodCall, + not, + ref, + str, + bool, + forEach, + list, + qref, + raw, + set, +} from 'graphql-mapping-template'; +import { getIdentityClaimExp, getOwnerClaim, apiKeyExpression, iamExpression, emptyPayload, setHasAuthExpression } from './helpers'; +import { + COGNITO_AUTH_TYPE, + OIDC_AUTH_TYPE, + RoleDefinition, + splitRoles, + ConfiguredAuthProviders, + IS_AUTHORIZED_FLAG, + fieldIsList, + QuerySource, +} from '../utils'; +import { InvalidDirectiveError } from '@aws-amplify/graphql-transformer-core'; +import { NONE_VALUE } from 'graphql-transformer-common'; + +const generateStaticRoleExpression = (roles: Array): Array => { + const staticRoleExpression: Array = []; + let privateRoleIdx = roles.findIndex(r => r.strategy === 'private'); + if (privateRoleIdx > -1) { + staticRoleExpression.push(set(ref(IS_AUTHORIZED_FLAG), bool(true))); + roles.splice(privateRoleIdx, 1); + } + if (roles.length > 0) { + staticRoleExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref('staticGroupRoles'), raw(JSON.stringify(roles.map(r => ({ claim: r.claim, entity: r.entity }))))), + forEach(ref('groupRole'), ref('staticGroupRoles'), [ + set(ref('groupsInToken'), getIdentityClaimExp(ref('groupRole.claim'), list([]))), + iff( + methodCall(ref('groupsInToken.contains'), ref('groupRole.entity')), + compoundExpression([set(ref(IS_AUTHORIZED_FLAG), bool(true)), raw(`#break`)]), + ), + ]), + ]), + ), + ); + } + return staticRoleExpression; +}; + +const generateAuthFilter = ( + roles: Array, + fields: ReadonlyArray, + querySource: QuerySource, +): Array => { + const authFilter = new Array(); + const groupMap = new Map>(); + const groupContainsExpression = new Array(); + if (!(roles.length > 0)) return []; + /** + * if ownerField is string + * ownerField: { eq: "cognito:owner" } + * if ownerField is a List + * ownerField: { contains: "cognito:owner"} + * + * if groupsField is a string + * groupsField: { in: "cognito:groups" } + * if groupsField is a list + * groupsField: { contains: "cognito:groups" } + * */ + if (querySource === 'dynamodb') { + for (let role of roles) { + const entityIsList = fieldIsList(fields, role.entity!); + if (role.strategy === 'owner') { + const ownerCondition = entityIsList ? 'contains' : 'eq'; + authFilter.push(obj({ [role.entity!]: obj({ [ownerCondition]: getOwnerClaim(role.claim!) }) })); + } + if (role.strategy === 'groups') { + // for fields where the group is a list and the token is a list we must add every group in the claim + if (entityIsList) { + if (groupMap.has(role.claim!)) { + groupMap.get(role.claim).push(role.entity); + } else { + groupMap.set(role.claim!, [role.entity]); + } + } else { + authFilter.push(obj({ [role.entity!]: obj({ in: getIdentityClaimExp(str(role.claim!), list([str(NONE_VALUE)])) }) })); + } + } + } + for (let [groupClaim, fieldList] of groupMap) { + groupContainsExpression.push( + forEach( + ref('group'), + ref(`util.defaultIfNull($ctx.identity.claims.get("${groupClaim}"), ["${NONE_VALUE}"])`), + fieldList.map(field => qref(methodCall(ref('authFilter.add'), raw(`{"${field}": { "contains": $group }}`)))), + ), + ); + } + return [ + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref('authFilter'), list(authFilter)), + ...(groupContainsExpression.length > 0 ? groupContainsExpression : []), + qref(methodCall(ref('ctx.stash.put'), str('authFilter'), raw('{ "or": $authFilter }'))), + ]), + ), + ]; + } + if (querySource === 'opensearch') { + for (let role of roles) { + let claimValue: Expression; + if (role.strategy === 'owner') { + claimValue = getOwnerClaim(role.claim!); + authFilter.push( + obj({ + terms_set: obj({ + [role.entity!]: obj({ + terms: list([claimValue]), + minimum_should_match_script: obj({ source: str('1') }), + }), + }), + }), + ); + } else if (role.strategy === 'groups') { + claimValue = getIdentityClaimExp(str(role.claim!), list([str(NONE_VALUE)])); + authFilter.push( + obj({ + terms_set: obj({ + [role.entity!]: obj({ + terms: claimValue, + minimum_should_match_script: obj({ source: str('1') }), + }), + }), + }), + ); + } + } + return [ + iff( + not(ref(IS_AUTHORIZED_FLAG)), + qref(methodCall(ref('ctx.stash.put'), str('authFilter'), obj({ bool: obj({ should: list(authFilter) }) }))), + ), + ]; + } + throw new InvalidDirectiveError(`Could not generate an auth filter for a ${querySource} datasource.`); +}; + +export const generateAuthExpressionForQueries = ( + providers: ConfiguredAuthProviders, + roles: Array, + fields: ReadonlyArray, + querySource: QuerySource = 'dynamodb', +): string => { + const { cogntoStaticRoles, cognitoDynamicRoles, oidcStaticRoles, oidcDynamicRoles, apiKeyRoles, iamRoles } = splitRoles(roles); + const totalAuthExpressions: Array = [setHasAuthExpression, set(ref(IS_AUTHORIZED_FLAG), bool(false))]; + if (providers.hasApiKey) { + totalAuthExpressions.push(apiKeyExpression(apiKeyRoles)); + } + if (providers.hasIAM) { + totalAuthExpressions.push(iamExpression(iamRoles, providers.hasAdminUIEnabled, providers.adminUserPoolID)); + } + if (providers.hasUserPools) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(COGNITO_AUTH_TYPE)), + compoundExpression([ + ...generateStaticRoleExpression(cogntoStaticRoles), + ...generateAuthFilter(cognitoDynamicRoles, fields, querySource), + ]), + ), + ); + } + if (providers.hasOIDC) { + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(OIDC_AUTH_TYPE)), + compoundExpression([ + ...generateAuthFilter(oidcDynamicRoles, fields, querySource), + ...generateStaticRoleExpression(oidcStaticRoles), + ]), + ), + ); + } + totalAuthExpressions.push( + iff( + and([not(ref(IS_AUTHORIZED_FLAG)), methodCall(ref('util.isNullOrEmpty'), methodCall(ref('ctx.stash.get'), str('authFilter')))]), + ref('util.unauthorized()'), + ), + ); + return printBlock('Authorization Steps')(compoundExpression([...totalAuthExpressions, emptyPayload])); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/resolvers/subscriptions.ts b/packages/amplify-graphql-auth-transformer/src/resolvers/subscriptions.ts new file mode 100644 index 00000000000..9f5add04279 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/resolvers/subscriptions.ts @@ -0,0 +1,65 @@ +import { + bool, + compoundExpression, + equals, + Expression, + iff, + methodCall, + not, + ref, + set, + str, + list, + nul, + printBlock, +} from 'graphql-mapping-template'; +import { COGNITO_AUTH_TYPE, ConfiguredAuthProviders, IS_AUTHORIZED_FLAG, OIDC_AUTH_TYPE, RoleDefinition, splitRoles } from '../utils'; +import { generateStaticRoleExpression, getOwnerClaim, apiKeyExpression, iamExpression, emptyPayload } from './helpers'; + +const dynamicRoleExpression = (roles: Array): Array => { + const ownerExpression = new Array(); + // we only check against owner rules which are not list fields + roles.forEach((role, idx) => { + if (role.strategy === 'owner') { + ownerExpression.push( + iff( + not(ref(IS_AUTHORIZED_FLAG)), + compoundExpression([ + set(ref(`ownerEntity${idx}`), methodCall(ref('util.defaultIfNull'), ref(`ctx.args.${role.entity!}`), nul())), + set(ref(`ownerClaim${idx}`), getOwnerClaim(role.claim!)), + iff(equals(ref(`ownerEntity${idx}`), ref(`ownerClaim${idx}`)), set(ref(IS_AUTHORIZED_FLAG), bool(true))), + ]), + ), + ); + } + }); + + return [...(ownerExpression.length > 0 ? ownerExpression : [])]; +}; + +export const generateAuthExpressionForSubscriptions = (providers: ConfiguredAuthProviders, roles: Array): string => { + const { cogntoStaticRoles, cognitoDynamicRoles, oidcStaticRoles, oidcDynamicRoles, iamRoles, apiKeyRoles } = splitRoles(roles); + const totalAuthExpressions: Array = [set(ref(IS_AUTHORIZED_FLAG), bool(false)), set(ref('allowedFields'), list([]))]; + if (providers.hasApiKey) { + totalAuthExpressions.push(apiKeyExpression(apiKeyRoles)); + } + if (providers.hasIAM) { + totalAuthExpressions.push(iamExpression(iamRoles, providers.hasAdminUIEnabled, providers.adminUserPoolID)); + } + if (providers.hasUserPools) + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(COGNITO_AUTH_TYPE)), + compoundExpression([...generateStaticRoleExpression(cogntoStaticRoles), ...dynamicRoleExpression(cognitoDynamicRoles)]), + ), + ); + if (providers.hasOIDC) + totalAuthExpressions.push( + iff( + equals(ref('util.authType()'), str(OIDC_AUTH_TYPE)), + compoundExpression([...generateStaticRoleExpression(oidcStaticRoles), ...dynamicRoleExpression(oidcDynamicRoles)]), + ), + ); + totalAuthExpressions.push(iff(not(ref(IS_AUTHORIZED_FLAG)), ref('util.unauthorized()'))); + return printBlock('Authorization Steps')(compoundExpression([...totalAuthExpressions, emptyPayload])); +}; diff --git a/packages/amplify-graphql-auth-transformer/src/utils/constants.ts b/packages/amplify-graphql-auth-transformer/src/utils/constants.ts new file mode 100644 index 00000000000..7b9d3cb428d --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/utils/constants.ts @@ -0,0 +1,32 @@ +import { AuthProvider, ModelOperation } from './definitions'; +export const DEFAULT_OWNER_FIELD = 'owner'; +export const DEFAULT_GROUPS_FIELD = 'groups'; +export const DEFAULT_IDENTITY_CLAIM = 'username'; +export const DEFAULT_COGNITO_IDENTITY_CLAIM = 'cognito:username'; +export const DEFAULT_GROUP_CLAIM = 'cognito:groups'; +export const ON_CREATE_FIELD = 'onCreate'; +export const ON_UPDATE_FIELD = 'onUpdate'; +export const ON_DELETE_FIELD = 'onDelete'; +export const AUTH_NON_MODEL_TYPES = 'authNonModelTypes'; +export const MODEL_OPERATIONS: ModelOperation[] = ['create', 'read', 'update', 'delete']; +export const AUTH_PROVIDER_DIRECTIVE_MAP = new Map([ + ['apiKey', 'aws_api_key'], + ['iam', 'aws_iam'], + ['oidc', 'aws_oidc'], + ['userPools', 'aws_cognito_user_pools'], +]); +// values for $util.authType() https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html +export const COGNITO_AUTH_TYPE = 'User Pool Authorization'; +export const OIDC_AUTH_TYPE = 'Open ID Connect Authorization'; +export const IAM_AUTH_TYPE = 'IAM Authorization'; +export const API_KEY_AUTH_TYPE = 'API Key Authorization'; +// resolver refs +export const IS_AUTHORIZED_FLAG = 'isAuthorized'; +export const ALLOWED_FIELDS = 'allowedFields'; +export const NULL_ALLOWED_FIELDS = 'nullAllowedFields'; +export const DENIED_FIELDS = 'deniedFields'; +// Admin Roles +export const ADMIN_ROLE = '_Full-access/CognitoIdentityCredentials'; +export const MANAGE_ROLE = '_Manage-only/CognitoIdentityCredentials'; +// resolver +export const NONE_DS = 'NONE_DS'; diff --git a/packages/amplify-graphql-auth-transformer/src/utils/definitions.ts b/packages/amplify-graphql-auth-transformer/src/utils/definitions.ts new file mode 100644 index 00000000000..786879c3b0e --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/utils/definitions.ts @@ -0,0 +1,99 @@ +import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; +export type AuthStrategy = 'owner' | 'groups' | 'public' | 'private'; +export type AuthProvider = 'apiKey' | 'iam' | 'oidc' | 'userPools'; +export type ModelQuery = 'get' | 'list'; +export type ModelMutation = 'create' | 'update' | 'delete'; +export type ModelOperation = 'create' | 'update' | 'delete' | 'read'; + +export type QuerySource = 'dynamodb' | 'opensearch'; +export interface SearchableConfig { + queries: { + search: string; + }; +} + +export interface RolesByProvider { + cogntoStaticRoles: Array; + cognitoDynamicRoles: Array; + oidcStaticRoles: Array; + oidcDynamicRoles: Array; + iamRoles: Array; + apiKeyRoles: Array; +} + +export interface AuthRule { + allow: AuthStrategy; + provider?: AuthProvider; + ownerField?: string; + identityClaim?: string; + groupsField?: string; + groupClaim?: string; + groups?: string[]; + operations?: ModelOperation[]; + // Used only for IAM provider to decide if an IAM policy needs to be generated. IAM auth with AdminUI does not need IAM policies + generateIAMPolicy?: boolean; +} + +export interface RoleDefinition { + provider: AuthProvider; + strategy: AuthStrategy; + static: boolean; + claim?: string; + entity?: string; + // specific to mutations + allowedFields?: Array; + nullAllowedFields?: Array; +} + +export interface AuthDirective { + rules: AuthRule[]; +} + +export interface ConfiguredAuthProviders { + default: AuthProvider; + onlyDefaultAuthProviderConfigured: boolean; + hasApiKey: boolean; + hasUserPools: boolean; + hasOIDC: boolean; + hasIAM: boolean; + hasAdminUIEnabled: boolean; + adminUserPoolID?: string; +} + +export interface AuthTransformerConfig { + addAwsIamAuthInOutputSchema: boolean; + authConfig?: AppSyncAuthConfiguration; + adminUserPoolID?: string; +} + +export const authDirectiveDefinition = ` + directive @auth(rules: [AuthRule!]!) on OBJECT | FIELD_DEFINITION + input AuthRule { + allow: AuthStrategy! + provider: AuthProvider + identityClaim: String + groupClaim: String + ownerField: String + groupsField: String + groups: [String] + operations: [ModelOperation] + } + enum AuthStrategy { + owner + groups + private + public + } + enum AuthProvider { + apiKey + iam + oidc + userPools + } + enum ModelOperation { + create + update + delete + read + } +`; diff --git a/packages/amplify-graphql-auth-transformer/src/utils/iam.ts b/packages/amplify-graphql-auth-transformer/src/utils/iam.ts new file mode 100644 index 00000000000..596f976ceb6 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/utils/iam.ts @@ -0,0 +1,70 @@ +import * as cdk from '@aws-cdk/core'; +interface PolicyDocument { + [key: string]: any; +} + +export const createPolicyDocumentForManagedPolicy = (resources: Set) => { + const policyDocuments = new Array(); + let policyDocumentResources = new Array(); + let resourceSize = 0; + + // 6144 bytes is the maximum policy payload size, but there is structural overhead, hence the 6000 bytes + const MAX_BUILT_SIZE_BYTES = 6000; + // The overhead is the amount of static policy arn contents like region, accountid, etc. + // arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/fields/${fieldName} + // 16 15 13 5 27 6 X+1 7 Y + // 89 + 11 extra = 100 + const RESOURCE_OVERHEAD = 100; + + const createPolicyDocument = (newPolicyDocumentResources: Array): PolicyDocument => { + return { + Version: '2012-10-17', + Statement: [ + { + Effect: 'Allow', + Action: ['appsync:GraphQL'], + Resource: newPolicyDocumentResources, + }, + ], + }; + }; + + for (const resource of resources) { + // We always have 2 parts, no need to check + const [typeName, fieldName] = resource.split('/'); + + if (fieldName !== 'null') { + policyDocumentResources.push( + cdk.Fn.sub('arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/fields/${fieldName}', { + apiId: cdk.Fn.getAtt('GraphQLAPI', 'ApiId').toString(), + typeName, + fieldName, + }).toString(), + ); + resourceSize += RESOURCE_OVERHEAD + typeName.length + fieldName.length; + } else { + policyDocumentResources.push( + cdk.Fn.sub('arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/*', { + apiId: cdk.Fn.getAtt('GraphQLAPI', 'ApiId').toString(), + typeName, + }).toString(), + ); + resourceSize = RESOURCE_OVERHEAD + typeName.length; + } + // + // Check size of resource and if needed create a new one and clear the resources and + // reset accumulated size + // + if (resourceSize > MAX_BUILT_SIZE_BYTES) { + const policyDocument = createPolicyDocument(policyDocumentResources.slice(0, policyDocumentResources.length - 1)); + policyDocuments.push(policyDocument); + // Remove all but the last item + policyDocumentResources = policyDocumentResources.slice(-1); + resourceSize = 0; + } + } + if (policyDocumentResources.length > 0) { + policyDocuments.push(createPolicyDocument(policyDocumentResources)); + } + return policyDocuments; +}; diff --git a/packages/amplify-graphql-auth-transformer/src/utils/index.ts b/packages/amplify-graphql-auth-transformer/src/utils/index.ts new file mode 100644 index 00000000000..1b67a600293 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/utils/index.ts @@ -0,0 +1,152 @@ +import { ModelDirectiveConfiguration, SubscriptionLevel } from '@aws-amplify/graphql-model-transformer'; +import { DirectiveWrapper } from '@aws-amplify/graphql-transformer-core'; +import { AppSyncAuthMode } from '@aws-amplify/graphql-transformer-interfaces'; +import { TransformerContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; +import { Stack } from '@aws-cdk/core'; +import { DirectiveNode, ObjectTypeDefinitionNode } from 'graphql'; +import { toCamelCase, plurality, graphqlName, toUpper } from 'graphql-transformer-common'; +import { + AuthProvider, + AuthRule, + AuthTransformerConfig, + ConfiguredAuthProviders, + RoleDefinition, + RolesByProvider, + SearchableConfig, +} from './definitions'; + +export * from './constants'; +export * from './definitions'; +export * from './validations'; +export * from './schema'; +export * from './iam'; + +export const splitRoles = (roles: Array): RolesByProvider => { + return { + cogntoStaticRoles: roles.filter(r => r.static && r.provider === 'userPools'), + cognitoDynamicRoles: roles.filter(r => !r.static && r.provider === 'userPools'), + oidcStaticRoles: roles.filter(r => r.static && r.provider === 'oidc'), + oidcDynamicRoles: roles.filter(r => !r.static && r.provider === 'oidc'), + iamRoles: roles.filter(r => r.provider === 'iam'), + apiKeyRoles: roles.filter(r => r.provider === 'apiKey'), + }; +}; +/** + * Ensure the following defaults + * - provider + * - iam policy generation + */ +export const ensureAuthRuleDefaults = (rules: AuthRule[]) => { + // We assign the default provider if an override is not present make further handling easier. + for (const rule of rules) { + if (!rule.provider) { + switch (rule.allow) { + case 'owner': + case 'groups': + rule.provider = 'userPools'; + break; + case 'private': + rule.provider = 'userPools'; + break; + case 'public': + rule.provider = 'apiKey'; + break; + default: + throw new Error(`Need to specify an allow to assigned a provider: ${rule}`); + } + } + // by default we generate an IAM policy for every rule + if (rule.provider === 'iam' && !rule.generateIAMPolicy) { + rule.generateIAMPolicy = true; + } + } +}; + +export const getModelConfig = (directive: DirectiveNode, typeName: string, isDataStoreEnabled = false): ModelDirectiveConfiguration => { + const directiveWrapped: DirectiveWrapper = new DirectiveWrapper(directive); + const options = directiveWrapped.getArguments({ + queries: { + get: toCamelCase(['get', typeName]), + list: toCamelCase(['list', plurality(typeName, true)]), + ...(isDataStoreEnabled ? { sync: toCamelCase(['sync', plurality(typeName, true)]) } : undefined), + }, + mutations: { + create: toCamelCase(['create', typeName]), + update: toCamelCase(['update', typeName]), + delete: toCamelCase(['delete', typeName]), + }, + subscriptions: { + level: SubscriptionLevel.on, + onCreate: [toCamelCase(['onCreate', typeName])], + onDelete: [toCamelCase(['onDelete', typeName])], + onUpdate: [toCamelCase(['onUpdate', typeName])], + }, + timestamps: { + createdAt: 'createdAt', + updatedAt: 'updatedAt', + }, + }); + return options; +}; + +export const getSearchableConfig = (directive: DirectiveNode, typeName: string): SearchableConfig | null => { + const directiveWrapped: DirectiveWrapper = new DirectiveWrapper(directive); + const options = directiveWrapped.getArguments({ + queries: { + search: graphqlName(`search${plurality(toUpper(typeName), true)}`), + }, + }); + return options; +}; +/** + * gets stack name if the field is paired with function, predictions, or by itself + */ +export const getStackForField = ( + ctx: TransformerContextProvider, + obj: ObjectTypeDefinitionNode, + fieldName: string, + hasModelDirective: boolean, +): Stack => { + const fieldNode = obj.fields.find(f => f.name.value === fieldName); + const fieldDirectives = fieldNode.directives.map(d => d.name.value); + if (fieldDirectives.includes('function')) { + return ctx.stackManager.getStack('FunctionDirectiveStack'); + } else if (fieldDirectives.includes('predictions')) { + return ctx.stackManager.getStack('PredictionsDirectiveStack'); + } else if (hasModelDirective) { + return ctx.stackManager.getStack(obj.name.value); + } else { + return ctx.stackManager.rootStack; + } +}; + +export const getConfiguredAuthProviders = (config: AuthTransformerConfig): ConfiguredAuthProviders => { + const providers = [ + config.authConfig.defaultAuthentication.authenticationType, + ...config.authConfig.additionalAuthenticationProviders.map(p => p.authenticationType), + ]; + const getAuthProvider = (authType: AppSyncAuthMode): AuthProvider => { + switch (authType) { + case 'AMAZON_COGNITO_USER_POOLS': + return 'userPools'; + case 'API_KEY': + return 'apiKey'; + case 'AWS_IAM': + return 'iam'; + case 'OPENID_CONNECT': + return 'oidc'; + } + }; + const hasIAM = providers.some(p => p === 'AWS_IAM'); + const configuredProviders: ConfiguredAuthProviders = { + default: getAuthProvider(config.authConfig.defaultAuthentication.authenticationType), + onlyDefaultAuthProviderConfigured: config.authConfig.additionalAuthenticationProviders.length === 0, + hasAdminUIEnabled: hasIAM && config.addAwsIamAuthInOutputSchema, + adminUserPoolID: config.adminUserPoolID!, + hasApiKey: providers.some(p => p === 'API_KEY'), + hasUserPools: providers.some(p => p === 'AMAZON_COGNITO_USER_POOLS'), + hasOIDC: providers.some(p => p === 'OPENID_CONNECT'), + hasIAM, + }; + return configuredProviders; +}; diff --git a/packages/amplify-graphql-auth-transformer/src/utils/schema.ts b/packages/amplify-graphql-auth-transformer/src/utils/schema.ts new file mode 100644 index 00000000000..d0cb99c4b0e --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/utils/schema.ts @@ -0,0 +1,209 @@ +import { ModelDirectiveConfiguration, SubscriptionLevel } from '@aws-amplify/graphql-model-transformer'; +import { + QueryFieldType, + MutationFieldType, + TransformerTransformSchemaStepContextProvider, +} from '@aws-amplify/graphql-transformer-interfaces'; +import { ObjectTypeDefinitionNode, FieldDefinitionNode, DirectiveNode, NamedTypeNode } from 'graphql'; +import { + blankObjectExtension, + extendFieldWithDirectives, + extensionWithDirectives, + isListType, + makeInputValueDefinition, + makeNamedType, + plurality, + toCamelCase, +} from 'graphql-transformer-common'; +import { RoleDefinition } from './definitions'; + +export const collectFieldNames = (object: ObjectTypeDefinitionNode): Array => { + return object.fields!.map((field: FieldDefinitionNode) => field.name.value); +}; + +export const fieldIsList = (fields: ReadonlyArray, fieldName: string) => { + return fields.some(field => field.name.value === fieldName && isListType(field.type)); +}; + +export const extendTypeWithDirectives = ( + ctx: TransformerTransformSchemaStepContextProvider, + typeName: string, + directives: Array, +): void => { + let objectTypeExtension = blankObjectExtension(typeName); + objectTypeExtension = extensionWithDirectives(objectTypeExtension, directives); + ctx.output.addObjectExtension(objectTypeExtension); +}; + +export const addDirectivesToField = ( + ctx: TransformerTransformSchemaStepContextProvider, + typeName: string, + fieldName: string, + directives: Array, +) => { + const type = ctx.output.getType(typeName) as ObjectTypeDefinitionNode; + if (type) { + const field = type.fields?.find(f => f.name.value === fieldName); + if (field) { + const newFields = [...type.fields!.filter(f => f.name.value !== field.name.value), extendFieldWithDirectives(field, directives)]; + + const newType = { + ...type, + fields: newFields, + }; + + ctx.output.putType(newType); + } + } +}; + +export const addSubscriptionArguments = ( + ctx: TransformerTransformSchemaStepContextProvider, + operationName: string, + subscriptionRoles: Array, +) => { + let subscription = ctx.output.getSubscription()!; + let createField: FieldDefinitionNode = subscription!.fields!.find(field => field.name.value === operationName) as FieldDefinitionNode; + const subcriptionArgumentList = subscriptionRoles.map(role => { + return makeInputValueDefinition(role.entity!, makeNamedType('String')); + }); + createField = { + ...createField, + arguments: subcriptionArgumentList, + }; + subscription = { + ...subscription, + fields: subscription!.fields!.map(field => (field.name.value === operationName ? createField : field)), + }; + ctx.output.putType(subscription); +}; + +export const addDirectivesToOperation = ( + ctx: TransformerTransformSchemaStepContextProvider, + typeName: string, + operationName: string, + directives: Array, +) => { + // add directives to the given operation + addDirectivesToField(ctx, typeName, operationName, directives); + + // add the directives to the result type of the operation + const type = ctx.output.getType(typeName) as ObjectTypeDefinitionNode; + if (type) { + const field = type.fields!.find(f => f.name.value === operationName); + + if (field) { + const returnFieldType = field.type as NamedTypeNode; + + if (returnFieldType.name) { + const returnTypeName = returnFieldType.name.value; + + extendTypeWithDirectives(ctx, returnTypeName, directives); + } + } + } +}; + +export const getQueryFieldNames = ( + modelDirectiveConfig: ModelDirectiveConfiguration, +): Set<{ fieldName: string; typeName: string; type: QueryFieldType }> => { + const fields: Set<{ fieldName: string; typeName: string; type: QueryFieldType }> = new Set(); + if (modelDirectiveConfig?.queries?.get) { + fields.add({ + typeName: 'Query', + fieldName: modelDirectiveConfig.queries.get, + type: QueryFieldType.GET, + }); + } + + if (modelDirectiveConfig?.queries?.list) { + fields.add({ + typeName: 'Query', + fieldName: modelDirectiveConfig.queries.list, + type: QueryFieldType.LIST, + }); + } + + if (modelDirectiveConfig?.queries?.sync) { + fields.add({ + typeName: 'Query', + fieldName: modelDirectiveConfig.queries.sync, + type: QueryFieldType.SYNC, + }); + } + return fields; +}; + +export const getMutationFieldNames = ( + modelDirectiveConfig: ModelDirectiveConfiguration, +): Set<{ fieldName: string; typeName: string; type: MutationFieldType }> => { + // Todo: get fields names from the directives + const getMutationType = (type: string): MutationFieldType => { + switch (type) { + case 'create': + return MutationFieldType.CREATE; + case 'update': + return MutationFieldType.UPDATE; + case 'delete': + return MutationFieldType.DELETE; + default: + throw new Error('Unknown mutation type'); + } + }; + + const fieldNames: Set<{ fieldName: string; typeName: string; type: MutationFieldType }> = new Set(); + for (let [mutationType, mutationName] of Object.entries(modelDirectiveConfig?.mutations || {})) { + if (mutationName) { + fieldNames.add({ + typeName: 'Mutation', + fieldName: mutationName, + type: getMutationType(mutationType), + }); + } + } + + return fieldNames; +}; + +export const getSubscriptionFieldNames = ( + modelDirectiveConfig: ModelDirectiveConfiguration, +): Set<{ + fieldName: string; + typeName: string; +}> => { + const fields: Set<{ + fieldName: string; + typeName: string; + }> = new Set(); + + if (modelDirectiveConfig?.subscriptions?.level === SubscriptionLevel.on) { + if (modelDirectiveConfig?.subscriptions?.onCreate && modelDirectiveConfig.mutations?.create) { + for (const fieldName of modelDirectiveConfig.subscriptions.onCreate) { + fields.add({ + typeName: 'Subscription', + fieldName: fieldName, + }); + } + } + + if (modelDirectiveConfig?.subscriptions?.onUpdate && modelDirectiveConfig.mutations?.update) { + for (const fieldName of modelDirectiveConfig.subscriptions.onUpdate) { + fields.add({ + typeName: 'Subscription', + fieldName: fieldName, + }); + } + } + + if (modelDirectiveConfig?.subscriptions?.onDelete && modelDirectiveConfig.mutations?.delete) { + for (const fieldName of modelDirectiveConfig.subscriptions.onDelete) { + fields.add({ + typeName: 'Subscription', + fieldName: fieldName, + }); + } + } + } + + return fields; +}; diff --git a/packages/amplify-graphql-auth-transformer/src/utils/validations.ts b/packages/amplify-graphql-auth-transformer/src/utils/validations.ts new file mode 100644 index 00000000000..d68646b90e9 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/src/utils/validations.ts @@ -0,0 +1,123 @@ +import { InvalidDirectiveError } from '@aws-amplify/graphql-transformer-core'; +import { AuthRule, ConfiguredAuthProviders } from './definitions'; + +export const validateRuleAuthStrategy = (rule: AuthRule, configuredAuthProviders: ConfiguredAuthProviders) => { + // + // Groups + // + if (rule.allow === 'groups' && rule.provider !== 'userPools' && rule.provider !== 'oidc') { + throw new InvalidDirectiveError( + `@auth directive with 'groups' strategy only supports 'userPools' and 'oidc' providers, but found '${rule.provider}' assigned.`, + ); + } + if (rule.allow === 'groups' && !rule.groups && !rule.groupsField) { + throw new InvalidDirectiveError(`@auth directive with 'groups' should have a defined groups list or a groupsField.`); + } + + // + // Owner + // + if (rule.allow === 'owner') { + if (rule.provider !== null && rule.provider !== 'userPools' && rule.provider !== 'oidc') { + throw new InvalidDirectiveError( + `@auth directive with 'owner' strategy only supports 'userPools' (default) and 'oidc' providers, but \ +found '${rule.provider}' assigned.`, + ); + } + } + + // + // Public + // + if (rule.allow === 'public') { + if (rule.provider !== null && rule.provider !== 'apiKey' && rule.provider !== 'iam') { + throw new InvalidDirectiveError( + `@auth directive with 'public' strategy only supports 'apiKey' (default) and 'iam' providers, but \ +found '${rule.provider}' assigned.`, + ); + } + } + + // + // Private + // + if (rule.allow === 'private') { + if (rule.provider !== null && rule.provider !== 'userPools' && rule.provider !== 'iam') { + throw new InvalidDirectiveError( + `@auth directive with 'private' strategy only supports 'userPools' (default) and 'iam' providers, but \ +found '${rule.provider}' assigned.`, + ); + } + } + + // + // Validate provider values against project configuration. + // + if (rule.provider === 'apiKey' && configuredAuthProviders.hasApiKey === false) { + throw new InvalidDirectiveError( + `@auth directive with 'apiKey' provider found, but the project has no API Key authentication provider configured.`, + ); + } else if (rule.provider === 'oidc' && configuredAuthProviders.hasOIDC === false) { + throw new InvalidDirectiveError( + `@auth directive with 'oidc' provider found, but the project has no OPENID_CONNECT authentication provider configured.`, + ); + } else if (rule.provider === 'userPools' && configuredAuthProviders.hasUserPools === false) { + throw new InvalidDirectiveError( + `@auth directive with 'userPools' provider found, but the project has no Cognito User Pools authentication provider configured.`, + ); + } else if (rule.provider === 'iam' && configuredAuthProviders.hasIAM === false) { + throw new InvalidDirectiveError( + `@auth directive with 'iam' provider found, but the project has no IAM authentication provider configured.`, + ); + } +}; + +export const validateRules = (rules: AuthRule[], configuredAuthProviders: ConfiguredAuthProviders) => { + for (const rule of rules) { + validateRuleAuthStrategy(rule, configuredAuthProviders); + commonRuleValidation(rule); + } +}; + +export const validateFieldRules = ( + rules: AuthRule[], + isParentTypeBuiltinType: boolean, + parentHasModelDirective: boolean, + authProviderConfig: ConfiguredAuthProviders, +) => { + for (const rule of rules) { + validateRuleAuthStrategy(rule, authProviderConfig); + + if (isParentTypeBuiltinType && rule.operations && rule.operations.length > 0) { + throw new InvalidDirectiveError( + `@auth rules on fields within Query, Mutation, Subscription cannot specify 'operations' argument as these rules \ +are already on an operation already.`, + ); + } + + if (!parentHasModelDirective && rule.operations && rule.operations.length > 0) { + throw new InvalidDirectiveError( + `@auth rules on fields within types that does not have @model directive cannot specify 'operations' argument as there are \ +operations will be generated by the CLI.`, + ); + } + + commonRuleValidation(rule); + } +}; + +// commmon rule validation between obj and field +export const commonRuleValidation = (rule: AuthRule) => { + const { identityClaim, allow, groups, groupsField, groupClaim } = rule; + if (allow === 'groups' && identityClaim) { + throw new InvalidDirectiveError(` + @auth identityClaim can only be used for 'allow: owner'`); + } + if (allow === 'owner' && groupClaim) { + throw new InvalidDirectiveError(` + @auth groupClaim can only be used 'allow: groups'`); + } + if (groupsField && groups) { + throw new InvalidDirectiveError('This rule has groupsField and groups, please use one or the other'); + } +}; diff --git a/packages/amplify-graphql-auth-transformer/tsconfig.json b/packages/amplify-graphql-auth-transformer/tsconfig.json new file mode 100644 index 00000000000..e00f8011a38 --- /dev/null +++ b/packages/amplify-graphql-auth-transformer/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "strict": false, // TODO enable + "rootDir": "src", + "outDir": "lib" + }, + "references": [ + {"path": "../amplify-graphql-transformer-interfaces"}, + {"path": "../amplify-graphql-transformer-core"}, + {"path": "../amplify-graphql-model-transformer"}, + {"path": "../graphql-mapping-template"}, + {"path": "../graphql-transformer-common"} + ] +} diff --git a/packages/amplify-graphql-function-transformer/src/__tests__/__snapshots__/amplify-graphql-function-transformer.test.ts.snap b/packages/amplify-graphql-function-transformer/src/__tests__/__snapshots__/amplify-graphql-function-transformer.test.ts.snap index cd54de62ac8..96ab67a114d 100644 --- a/packages/amplify-graphql-function-transformer/src/__tests__/__snapshots__/amplify-graphql-function-transformer.test.ts.snap +++ b/packages/amplify-graphql-function-transformer/src/__tests__/__snapshots__/amplify-graphql-function-transformer.test.ts.snap @@ -3,7 +3,7 @@ exports[`it generates the expected resources 1`] = ` Object { "InvokeEchofunctionLambdaDataSource.req.vtl": "## [Start] Invoke AWS Lambda data source: EchofunctionLambdaDataSource. ** -{ +$util.toJson({ \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Invoke\\", \\"payload\\": { @@ -15,7 +15,7 @@ Object { \\"request\\": $util.toJson($ctx.request), \\"prev\\": $util.toJson($ctx.prev) } -} +}) ## [End] Invoke AWS Lambda data source: EchofunctionLambdaDataSource. **", "InvokeEchofunctionLambdaDataSource.res.vtl": "## [Start] Handle error or return result. ** #if( $ctx.error ) @@ -23,11 +23,6 @@ Object { #end $util.toJson($ctx.result) ## [End] Handle error or return result. **", - "Query.echo.req.vtl": "## [Start] Stash resolver specific context.. ** -$util.qr($ctx.stash.put(\\"typeName\\", \\"Query\\")) -$util.qr($ctx.stash.put(\\"fieldName\\", \\"echo\\")) -{} -## [End] Stash resolver specific context.. **", "Query.echo.res.vtl": "$util.toJson($ctx.prev.result)", } `; diff --git a/packages/amplify-graphql-function-transformer/src/__tests__/amplify-graphql-function-transformer.test.ts b/packages/amplify-graphql-function-transformer/src/__tests__/amplify-graphql-function-transformer.test.ts index 7f0ee96fc67..4f3dc104065 100644 --- a/packages/amplify-graphql-function-transformer/src/__tests__/amplify-graphql-function-transformer.test.ts +++ b/packages/amplify-graphql-function-transformer/src/__tests__/amplify-graphql-function-transformer.test.ts @@ -116,9 +116,7 @@ test('it generates the expected resources', () => { PipelineConfig: { Functions: [{ 'Fn::GetAtt': [anything(), 'FunctionId'] }], }, - RequestMappingTemplateS3Location: { - 'Fn::Join': ['', ['s3://', { Ref: anything() }, '/', { Ref: anything() }, '/pipelineFunctions/Query.echo.req.vtl']], - }, + RequestMappingTemplate: anything(), ResponseMappingTemplateS3Location: { 'Fn::Join': ['', ['s3://', { Ref: anything() }, '/', { Ref: anything() }, '/pipelineFunctions/Query.echo.res.vtl']], }, diff --git a/packages/amplify-graphql-function-transformer/src/graphql-function-transformer.ts b/packages/amplify-graphql-function-transformer/src/graphql-function-transformer.ts index c6a193ddd58..2fd2e60cd5b 100644 --- a/packages/amplify-graphql-function-transformer/src/graphql-function-transformer.ts +++ b/packages/amplify-graphql-function-transformer/src/graphql-function-transformer.ts @@ -1,8 +1,15 @@ -import { DirectiveWrapper, MappingTemplate, TransformerPluginBase } from '@aws-amplify/graphql-transformer-core'; +import { + DirectiveWrapper, + IAM_AUTH_ROLE_PARAMETER, + IAM_UNAUTH_ROLE_PARAMETER, + MappingTemplate, + TransformerPluginBase, +} from '@aws-amplify/graphql-transformer-core'; import { TransformerContextProvider, TransformerSchemaVisitStepContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; import * as lambda from '@aws-cdk/aws-lambda'; +import { AuthorizationType } from '@aws-cdk/aws-appsync'; import * as cdk from '@aws-cdk/core'; -import { obj, str, ref, printBlock, compoundExpression, qref, raw, iff } from 'graphql-mapping-template'; +import { obj, str, toJson, ref, printBlock, compoundExpression, qref, raw, iff, Expression } from 'graphql-mapping-template'; import { FunctionResourceIDs, ResolverResourceIDs, ResourceConstants } from 'graphql-transformer-common'; import { DirectiveNode, ObjectTypeDefinitionNode, InterfaceTypeDefinitionNode, FieldDefinitionNode } from 'graphql'; @@ -88,19 +95,21 @@ export class FunctionTransformer extends TransformerPluginBase { functionId, MappingTemplate.s3MappingTemplateFromString( printBlock(`Invoke AWS Lambda data source: ${dataSourceId}`)( - obj({ - version: str('2018-05-29'), - operation: str('Invoke'), - payload: obj({ - typeName: ref('ctx.stash.get("typeName")'), - fieldName: ref('ctx.stash.get("fieldName")'), - arguments: ref('util.toJson($ctx.arguments)'), - identity: ref('util.toJson($ctx.identity)'), - source: ref('util.toJson($ctx.source)'), - request: ref('util.toJson($ctx.request)'), - prev: ref('util.toJson($ctx.prev)'), + toJson( + obj({ + version: str('2018-05-29'), + operation: str('Invoke'), + payload: obj({ + typeName: ref('ctx.stash.get("typeName")'), + fieldName: ref('ctx.stash.get("fieldName")'), + arguments: ref('util.toJson($ctx.arguments)'), + identity: ref('util.toJson($ctx.identity)'), + source: ref('util.toJson($ctx.source)'), + request: ref('util.toJson($ctx.request)'), + prev: ref('util.toJson($ctx.prev)'), + }), }), - }), + ), ), `${functionId}.req.vtl`, ), @@ -124,20 +133,37 @@ export class FunctionTransformer extends TransformerPluginBase { const resolverId = ResolverResourceIDs.ResolverResourceID(config.resolverTypeName, config.resolverFieldName); let resolver = createdResources.get(resolverId); + const requestTemplate: Array = [ + qref(`$ctx.stash.put("typeName", "${config.resolverTypeName}")`), + qref(`$ctx.stash.put("fieldName", "${config.resolverFieldName}")`), + ]; + const authModes = [context.authConfig.defaultAuthentication, ...(context.authConfig.additionalAuthenticationProviders || [])].map( + mode => mode?.authenticationType, + ); + if (authModes.includes(AuthorizationType.IAM)) { + const authRoleParameter = (context.stackManager.getParameter(IAM_AUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString; + const unauthRoleParameter = (context.stackManager.getParameter(IAM_UNAUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString; + requestTemplate.push( + qref( + `$ctx.stash.put("authRole", "arn:aws:sts::${ + cdk.Stack.of(context.stackManager.rootStack).account + }:assumed-role/${authRoleParameter}/CognitoIdentityCredentials")`, + ), + qref( + `$ctx.stash.put("unauthRole", "arn:aws:sts::${ + cdk.Stack.of(context.stackManager.rootStack).account + }:assumed-role/${unauthRoleParameter}/CognitoIdentityCredentials")`, + ), + ); + } + requestTemplate.push(obj({})); + if (resolver === undefined) { + // TODO: update function to use resolver manager resolver = context.api.host.addResolver( config.resolverTypeName, config.resolverFieldName, - MappingTemplate.s3MappingTemplateFromString( - printBlock('Stash resolver specific context.')( - compoundExpression([ - qref(`$ctx.stash.put("typeName", "${config.resolverTypeName}")`), - qref(`$ctx.stash.put("fieldName", "${config.resolverFieldName}")`), - obj({}), - ]), - ), - `${config.resolverTypeName}.${config.resolverFieldName}.req.vtl`, - ), + MappingTemplate.inlineTemplateFromString(printBlock('Stash resolver specific context.')(compoundExpression(requestTemplate))), MappingTemplate.s3MappingTemplateFromString( '$util.toJson($ctx.prev.result)', `${config.resolverTypeName}.${config.resolverFieldName}.res.vtl`, @@ -146,7 +172,6 @@ export class FunctionTransformer extends TransformerPluginBase { [], stack, ); - createdResources.set(resolverId, resolver); } @@ -159,7 +184,7 @@ export class FunctionTransformer extends TransformerPluginBase { function lambdaArnResource(env: cdk.CfnParameter, name: string, region?: string): string { const substitutions: { [key: string]: string } = {}; if (name.includes('${env}')) { - substitutions.env = (env as unknown) as string; + substitutions.env = env as unknown as string; } return cdk.Fn.conditionIf( ResourceConstants.CONDITIONS.HasEnvironmentParameter, diff --git a/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-index-transformer.test.ts.snap b/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-index-transformer.test.ts.snap index 094ac57e866..bd380a65119 100644 --- a/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-index-transformer.test.ts.snap +++ b/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-index-transformer.test.ts.snap @@ -13,7 +13,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -124,14 +130,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -201,13 +214,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -217,7 +231,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -373,35 +393,64 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", "Query.listByEmailKindDate.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -520,12 +569,38 @@ $util.toJson($GetRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.listByEmailKindDate.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -535,8 +610,20 @@ $util.toJson($ctx.result)", #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -560,13 +647,13 @@ $util.toJson($ctx.result)", #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.testsByCategory.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -639,12 +726,77 @@ $util.toJson($ListRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByCategory.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -661,7 +813,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -772,14 +930,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -849,13 +1014,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -865,7 +1031,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1021,35 +1193,64 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", "Query.listByEmailKindDate.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -1168,12 +1369,38 @@ $util.toJson($GetRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.listByEmailKindDate.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -1183,8 +1410,20 @@ $util.toJson($ctx.result)", #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1208,13 +1447,58 @@ $util.toJson($ctx.result)", #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -1231,7 +1515,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1342,14 +1632,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1419,13 +1716,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -1435,7 +1733,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1591,35 +1895,64 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", "Query.listByEmailKindDate.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -1738,12 +2071,38 @@ $util.toJson($GetRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.listByEmailKindDate.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -1753,8 +2112,20 @@ $util.toJson($ctx.result)", #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1778,13 +2149,13 @@ $util.toJson($ctx.result)", #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.testsByCategory.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -1857,7 +2228,27 @@ $util.toJson($ListRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByCategory.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) @@ -1895,12 +2286,77 @@ $util.toJson($ctx.result)", #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByEmail.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -2136,7 +2592,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2232,14 +2694,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2307,13 +2776,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2323,7 +2793,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2464,14 +2940,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email), \\"createdAt\\": $util.dynamodb.toDynamoDB($ctx.args.createdAt) @@ -2481,25 +2964,47 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", "Query.listByEmailKindDate.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -2618,13 +3123,39 @@ $util.toJson($GetRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end -$util.toJson($QueryRequest)", - "Query.listByEmailKindDate.res.vtl": "#if( $ctx.error ) - $util.error($ctx.error.message, $ctx.error.type) -#end -$util.toJson($ctx.result)", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end +$util.toJson($QueryRequest)", + "Query.listByEmailKindDate.res.vtl": "#if( $ctx.error ) + $util.error($ctx.error.message, $ctx.error.type) +#end +$util.toJson($ctx.result)", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.email) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'email'.\\", \\"InvalidArgumentsError\\") #end @@ -2695,8 +3226,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -2720,13 +3263,13 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.testsByCategory.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -2799,7 +3342,27 @@ $util.toJson($ListRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByCategory.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) @@ -2837,12 +3400,77 @@ $util.toJson($ctx.result)", #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByEmail.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -7865,7 +8493,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.addContentToCategory.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.addContentToCategory.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.addContentToCategory.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -7976,13 +8610,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"ContentCategory\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.addContentToCategory.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.addContentToCategory.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createBlog.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -7994,6 +8629,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createBlog.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8078,13 +8719,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Blog\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createBlog.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createBlog.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createItem.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8096,7 +8738,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createItem.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createItem.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8199,13 +8847,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Item\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createItem.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createItem.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8217,7 +8866,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8313,13 +8968,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTodo.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8331,6 +8987,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createTodo.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8415,13 +9077,20 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Todo\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTodo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTodo.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteBlog.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -8479,14 +9148,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteBlog.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteBlog.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteContentFromCategory.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteContentFromCategory.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteContentFromCategory.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8556,14 +9232,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteContentFromCategory.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteContentFromCategory.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteItem.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteItem.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8631,14 +9314,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteItem.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteItem.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8706,13 +9396,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteTodo.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -8770,13 +9467,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTodo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTodo.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateBlog.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8786,6 +9484,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateBlog.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -8915,13 +9619,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateBlog.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateBlog.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateItem.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8931,7 +9636,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateItem.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateItem.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9079,13 +9790,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateItem.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateItem.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -9095,7 +9807,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9236,13 +9954,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTodo.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -9252,6 +9971,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateTodo.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -9381,13 +10106,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTodo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTodo.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.byCreatedAt.req.vtl": "## [Start] Set query expression for key ** #if( !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"sortDirection is not supported for List operations without a Sort key defined.\\", \\"InvalidArgumentsError\\") @@ -9420,35 +10146,89 @@ $util.toJson($UpdateItem) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.byCreatedAt.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Query.getBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getBlog.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getBlog.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getBlog.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.getItem.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] Get Response template. **", + "Query.getItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getItem.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"orderId\\": $util.dynamodb.toDynamoDB($ctx.args.orderId), \\"status#createdAt\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.status}#\${ctx.args.createdAt}\\") @@ -9458,26 +10238,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getItem.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getItem.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getItem.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] Get Response template. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email), \\"createdAt\\": $util.dynamodb.toDynamoDB($ctx.args.createdAt) @@ -9487,47 +10295,97 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTodo.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTodo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTodo.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", "Query.itemsByCreatedAt.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -9600,7 +10458,27 @@ $util.toJson($GetRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.itemsByCreatedAt.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) @@ -9678,12 +10556,38 @@ $util.toJson($ctx.result)", #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.itemsByStatus.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Query.listBlogs.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listBlogs.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9693,8 +10597,20 @@ $util.toJson($ctx.result)", #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9718,13 +10634,13 @@ $util.toJson($ctx.result)", #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listBlogs.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listBlogs.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.listByEmailKindDate.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -9843,7 +10759,27 @@ $util.toJson($ListRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.listByEmailKindDate.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) @@ -9984,13 +10920,39 @@ $util.toJson($ctx.result)", #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.listContentByCategory.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", - "Query.listItems.postAuth.1.req.vtl": "## [Start] Set query expression for key ** + "Query.listItems.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listItems.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.orderId) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'orderId'.\\", \\"InvalidArgumentsError\\") #end @@ -10107,8 +11069,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -10132,14 +11106,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listItems.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listItems.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] ResponseTemplate. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.email) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'email'.\\", \\"InvalidArgumentsError\\") #end @@ -10210,8 +11190,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -10235,13 +11227,13 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.testsByCategory.req.vtl": "## [Start] Set query expression for key ** #set( $modelQueryExpression = {} ) ## [Start] Validate key arguments. ** @@ -10314,7 +11306,27 @@ $util.toJson($ListRequest) #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByCategory.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) @@ -10352,7 +11364,27 @@ $util.toJson($ctx.result)", #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByEmail.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) @@ -10430,11 +11462,241 @@ $util.toJson($ctx.result)", #set( $QueryRequest.scanIndexForward = true ) #end #if( $context.args.nextToken ) #set( $QueryRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) #set( $QueryRequest.filter = $util.parseJson(\\"$util.transform.toDynamoDBFilterExpression($ctx.args.filter)\\") ) #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $QueryRequest.filter = $filterExpression ) + #end +#end $util.toJson($QueryRequest)", "Query.testsByEmailByUpdatedAt.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)", + "Subscription.onCreateBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateBlog.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateBlog.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onCreateContentCategory.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateContentCategory.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateContentCategory.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onCreateItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateItem.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateItem.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onCreateTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTodo.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTodo.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteBlog.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteBlog.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteContentCategory.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteContentCategory.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteContentCategory.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteItem.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteItem.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTodo.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTodo.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateBlog.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateBlog.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateBlog.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateItem.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateItem.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateItem.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTodo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTodo.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTodo.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; diff --git a/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-primary-key-transformer.test.ts.snap b/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-primary-key-transformer.test.ts.snap index 327c5ae5eca..363263ed2ec 100644 --- a/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-primary-key-transformer.test.ts.snap +++ b/packages/amplify-graphql-index-transformer/src/__tests__/__snapshots__/amplify-graphql-primary-key-transformer.test.ts.snap @@ -13,7 +13,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -116,14 +122,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -191,13 +204,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -207,7 +221,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -355,14 +375,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email), \\"kind#other\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.kind}#\${ctx.args.other}\\") @@ -372,26 +399,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.email) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'email'.\\", \\"InvalidArgumentsError\\") #end @@ -508,8 +563,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -533,13 +600,58 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -556,7 +668,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -652,14 +770,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -727,13 +852,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -743,7 +869,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -884,14 +1016,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email), \\"kind\\": $util.dynamodb.toDynamoDB($ctx.args.kind) @@ -901,26 +1040,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.email) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'email'.\\", \\"InvalidArgumentsError\\") #end @@ -991,8 +1158,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1016,13 +1195,58 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -1039,7 +1263,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1134,14 +1364,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1208,13 +1445,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -1224,7 +1462,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1364,14 +1608,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email) })) @@ -1380,26 +1631,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"sortDirection is not supported for List operations without a Sort key defined.\\", \\"InvalidArgumentsError\\") #end @@ -1427,8 +1706,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1452,13 +1743,58 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -1475,7 +1811,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1571,14 +1913,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1646,13 +1995,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -1662,7 +2012,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -1803,14 +2159,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"status\\": $util.dynamodb.toDynamoDB($ctx.args.status), \\"lastStatus\\": $util.dynamodb.toDynamoDB($ctx.args.lastStatus) @@ -1820,26 +2183,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.status) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'status'.\\", \\"InvalidArgumentsError\\") #end @@ -1910,8 +2301,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1935,13 +2338,58 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -1958,7 +2406,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2054,14 +2508,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2129,13 +2590,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.testCreate.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -2147,7 +2609,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.testCreate.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.testCreate.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.testCreate.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2243,14 +2711,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.testCreate.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.testCreate.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.testDelete.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.testDelete.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.testDelete.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2318,13 +2793,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.testDelete.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.testDelete.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.testUpdate.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2334,7 +2810,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.testUpdate.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.testUpdate.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.testUpdate.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2475,13 +2957,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.testUpdate.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.testUpdate.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2491,7 +2974,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2632,14 +3121,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email) })) @@ -2648,26 +3144,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"sortDirection is not supported for List operations without a Sort key defined.\\", \\"InvalidArgumentsError\\") #end @@ -2695,8 +3219,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -2720,14 +3256,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.testGet.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.testGet.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.testGet.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id), \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email) @@ -2737,26 +3279,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.testGet.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.testGet.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.testGet.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.testList.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.testList.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.testList.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") #end @@ -2827,8 +3397,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -2852,13 +3434,58 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.testList.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.testList.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; @@ -2875,7 +3502,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -2970,14 +3603,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -3044,13 +3684,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.testCreate.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -3062,7 +3703,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.testCreate.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.testCreate.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.testCreate.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -3158,14 +3805,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.testCreate.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.testCreate.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.testDelete.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.testDelete.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.testDelete.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -3233,13 +3887,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.testDelete.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.testDelete.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.testUpdate.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -3249,7 +3904,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.testUpdate.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.testUpdate.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.testUpdate.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -3390,13 +4051,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.testUpdate.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.testUpdate.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -3406,7 +4068,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -3546,14 +4214,21 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.getTest.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email) })) @@ -3562,26 +4237,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", - "Query.listTests.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTests.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"sortDirection is not supported for List operations without a Sort key defined.\\", \\"InvalidArgumentsError\\") #end @@ -3609,8 +4312,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3634,14 +4349,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.testGet.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] ResponseTemplate. **", + "Query.testGet.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.testGet.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id), \\"email\\": $util.dynamodb.toDynamoDB($ctx.args.email) @@ -3651,26 +4372,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.testGet.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.testGet.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.testGet.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.testList.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.testList.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.testList.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") #end @@ -3741,8 +4490,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3766,12 +4527,57 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.testList.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.testList.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Resonse template. ** +$util.toJson(null) +## [End] Subscription Resonse template. **", } `; diff --git a/packages/amplify-graphql-index-transformer/src/resolvers.ts b/packages/amplify-graphql-index-transformer/src/resolvers.ts index d2bc85396b5..699472a0c8f 100644 --- a/packages/amplify-graphql-index-transformer/src/resolvers.ts +++ b/packages/amplify-graphql-index-transformer/src/resolvers.ts @@ -12,13 +12,17 @@ import { bool, compoundExpression, DynamoDBMappingTemplate, + equals, Expression, forEach, ifElse, iff, + int, + isNullOrEmpty, list, methodCall, nul, + not, obj, print, printBlock, @@ -302,7 +306,7 @@ function setQuerySnippet(config: PrimaryKeyDirectiveConfiguration, ctx: Transfor expressions.push( set(ref(ResourceConstants.SNIPPETS.ModelQueryExpression), obj({})), - applyKeyExpressionForCompositeKey(keyNames, keyTypes, ResourceConstants.SNIPPETS.ModelQueryExpression), + applyKeyExpressionForCompositeKey(keyNames, keyTypes, ResourceConstants.SNIPPETS.ModelQueryExpression)!, ); return block(`Set query expression for key`, expressions); @@ -427,6 +431,7 @@ function makeQueryResolver(config: IndexDirectiveConfiguration, ctx: Transformer const dataSource = ctx.api.host.getDataSource(`${object.name.value}Table`); const queryTypeName = ctx.output.getQueryTypeName() as string; const table = getTable(ctx, object); + const authFilter = ref('ctx.stash.authFilter'); const requestVariable = 'QueryRequest'; assert(dataSource); @@ -457,10 +462,35 @@ function makeQueryResolver(config: IndexDirectiveConfiguration, ctx: Transformer set(ref(`${requestVariable}.scanIndexForward`), bool(true)), ), iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken')), true), + ifElse( + not(isNullOrEmpty(authFilter)), + compoundExpression([ + set(ref('filter'), authFilter), + iff( + not(isNullOrEmpty(ref('ctx.args.filter'))), + set(ref('filter'), obj({ and: list([ref('filter'), ref('ctx.args.filter')]) })), + ), + ]), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), ref('ctx.args.filter'))), + ), iff( - ref('context.args.filter'), - set(ref(`${requestVariable}.filter`), ref('util.parseJson("$util.transform.toDynamoDBFilterExpression($ctx.args.filter)")')), - true, + not(isNullOrEmpty(ref('filter'))), + compoundExpression([ + set( + ref(`filterExpression`), + methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), ref('filter'))), + ), + iff( + not(methodCall(ref('util.isNullOrBlank'), ref('filterExpression.expression'))), + compoundExpression([ + iff( + equals(methodCall(ref('filterEpression.expressionValues.size')), int(0)), + qref(methodCall(ref('filterEpression.remove'), str('expressionValues'))), + ), + set(ref(`${requestVariable}.filter`), ref(`filterExpression`)), + ]), + ), + ]), ), raw(`$util.toJson($${requestVariable})`), ]), @@ -522,7 +552,7 @@ function addIndexToResolverSlot(resolver: TransformerResolverProvider, lines: st const res = resolver as any; res.addToSlot( - 'postAuth', + 'preAuth', MappingTemplate.s3MappingTemplateFromString( lines.join('\n') + '\n' + (!isSync ? '{}' : ''), `${res.typeName}.${res.fieldName}.{slotName}.{slotIndex}.req.vtl`, diff --git a/packages/amplify-graphql-index-transformer/src/schema.ts b/packages/amplify-graphql-index-transformer/src/schema.ts index 759b1d24800..3ffb35f72ce 100644 --- a/packages/amplify-graphql-index-transformer/src/schema.ts +++ b/packages/amplify-graphql-index-transformer/src/schema.ts @@ -322,6 +322,16 @@ export function ensureQueryField(config: IndexDirectiveConfiguration, ctx: Trans if (!queryField) { return; } + // add query field to metadata + const keyName = `${object.name.value}:indicies`; + let indicies: Set; + if (!ctx.metadata.has(keyName)) { + indicies = new Set([queryField]); + } else { + indicies = ctx.metadata.get>(keyName)!; + indicies.add(queryField); + } + ctx.metadata.set(keyName, indicies); const args = [createHashField(config)]; diff --git a/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap b/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap index cedcc76d586..eacbd1bf352 100644 --- a/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap +++ b/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap @@ -583,7 +583,7 @@ input DeleteCommentInput { " `; -exports[`ModelTransformer: should generate sync resolver with ConflictHandlerType.AUTOMERGE 1`] = ` +exports[`ModelTransformer: should generate sync resolver with ConflictHandlerType.Automerge 1`] = ` Object { "Mutation.createAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) @@ -596,6 +596,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createAuthor.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -680,13 +686,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Author\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -698,6 +705,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createComment.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -782,13 +795,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Comment\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createEmail.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -800,6 +814,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createEmail.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -884,13 +904,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Email\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -902,6 +923,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -986,13 +1013,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createRequire.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -1004,6 +1032,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createRequire.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -1088,13 +1122,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Require\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -1106,6 +1141,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createTest.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -1190,13 +1231,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -1208,6 +1250,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createUser.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -1292,13 +1340,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"User\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.customCreatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -1310,6 +1359,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.customCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customCreatePost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -1394,13 +1449,20 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.customCreatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customCreatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.customDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customDeletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1458,13 +1520,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.customDeletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customDeletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.customUpdatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -1474,6 +1537,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.customUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customUpdatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -1603,13 +1672,20 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.customUpdatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customUpdatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteAuthor.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1667,13 +1743,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteComment.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1731,13 +1814,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteEmail.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1795,13 +1885,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1860,13 +1957,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) $util.qr($DeleteRequest.put(\\"_version\\", $util.defaultIfNull($ctx.args.input[\\"_version\\"], \\"0\\"))) $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteRequire.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1924,13 +2028,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteTest.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -1988,13 +2099,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteUser.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -2052,13 +2170,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2068,6 +2187,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateAuthor.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -2197,13 +2322,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2213,6 +2339,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateComment.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -2342,13 +2474,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateEmail.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2358,6 +2491,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateEmail.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -2487,13 +2626,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2503,6 +2643,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -2633,13 +2779,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateRequire.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2649,6 +2796,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateRequire.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -2778,13 +2931,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2794,6 +2948,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateTest.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -2923,13 +3083,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -2939,6 +3100,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateUser.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -3068,35 +3235,70 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.customGetPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.customGetPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.customGetPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.customGetPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.customListPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.customListPost.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3106,8 +3308,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3131,189 +3345,419 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.customListPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.customListPost.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getAuthor.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getAuthor.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getComment.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getComment.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getEmail.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getEmail.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getEntity.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getEntity.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getEntity.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getEntity.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getRequire.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getRequire.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getUser.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getUser.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.listAuthors.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listAuthors.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3323,8 +3767,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3348,13 +3804,19 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listAuthors.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listAuthors.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listComments.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listComments.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3364,8 +3826,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3389,13 +3863,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listComments.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listComments.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listEmails.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listEmails.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3405,8 +3885,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3430,13 +3922,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listEmails.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listEmails.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listPosts.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3446,8 +3944,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3471,13 +3981,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listRequires.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listRequires.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3487,8 +4003,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3512,13 +4040,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listRequires.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listRequires.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3528,8 +4062,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3553,13 +4099,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listUsers.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listUsers.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -3569,8 +4121,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -3594,19 +4158,46 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listUsers.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listUsers.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.syncPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.syncPosts.req.vtl": "## [Start] Sync Request template. ** +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end +#end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Sync\\", - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -3615,17 +4206,332 @@ null \\"nextToken\\": $util.toJson($util.defaultIfNull($ctx.args.nextToken, null)) } ## [End] Sync Request template. **", - "Query.syncPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.syncPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", } `; -exports[`ModelTransformer: should generate sync resolver with ConflictHandlerType.LAMBDA 1`] = ` +exports[`ModelTransformer: should generate sync resolver with ConflictHandlerType.Lambda 1`] = ` Object { "Mutation.createAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) @@ -3638,6 +4544,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createAuthor.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -3722,13 +4634,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Author\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -3740,6 +4653,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createComment.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -3824,13 +4743,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Comment\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createEmail.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -3842,6 +4762,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createEmail.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -3926,13 +4852,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Email\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -3944,6 +4871,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -4028,13 +4961,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createRequire.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -4046,6 +4980,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createRequire.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -4130,13 +5070,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Require\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -4148,6 +5089,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createTest.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -4232,13 +5179,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -4250,6 +5198,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createUser.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -4334,13 +5288,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"User\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.customCreatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -4352,6 +5307,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.customCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customCreatePost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -4436,13 +5397,20 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.customCreatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customCreatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.customDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customDeletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -4500,13 +5468,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.customDeletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customDeletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.customUpdatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -4516,6 +5485,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.customUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customUpdatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -4645,13 +5620,20 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.customUpdatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customUpdatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteAuthor.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -4709,13 +5691,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteComment.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -4773,13 +5762,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteEmail.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -4837,13 +5833,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -4902,13 +5905,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) $util.qr($DeleteRequest.put(\\"_version\\", $util.defaultIfNull($ctx.args.input[\\"_version\\"], \\"0\\"))) $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteRequire.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -4966,13 +5976,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteTest.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -5030,13 +6047,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteUser.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -5094,13 +6118,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5110,6 +6135,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateAuthor.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -5239,13 +6270,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5255,6 +6287,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateComment.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -5384,13 +6422,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateEmail.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5400,6 +6439,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateEmail.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -5529,13 +6574,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5545,6 +6591,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -5675,13 +6727,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateRequire.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5691,6 +6744,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateRequire.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -5820,13 +6879,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5836,6 +6896,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateTest.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -5965,13 +7031,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -5981,6 +7048,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateUser.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -6110,35 +7183,70 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.customGetPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.customGetPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.customGetPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.customGetPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.customListPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.customListPost.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6148,8 +7256,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6173,189 +7293,419 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.customListPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.customListPost.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getAuthor.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getAuthor.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getComment.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getComment.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getEmail.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getEmail.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getEntity.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getEntity.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getEntity.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getEntity.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getRequire.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getRequire.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getUser.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getUser.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.listAuthors.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listAuthors.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6365,8 +7715,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6390,13 +7752,19 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listAuthors.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listAuthors.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listComments.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listComments.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6406,8 +7774,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6431,13 +7811,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listComments.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listComments.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listEmails.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listEmails.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6447,8 +7833,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6472,13 +7870,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listEmails.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listEmails.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listPosts.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6488,8 +7892,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6513,13 +7929,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listRequires.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listRequires.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6529,8 +7951,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6554,13 +7988,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listRequires.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listRequires.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6570,8 +8010,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6595,13 +8047,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listUsers.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listUsers.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -6611,8 +8069,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -6636,19 +8106,46 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listUsers.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listUsers.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.syncPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.syncPosts.req.vtl": "## [Start] Sync Request template. ** +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end +#end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Sync\\", - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -6657,17 +8154,332 @@ null \\"nextToken\\": $util.toJson($util.defaultIfNull($ctx.args.nextToken, null)) } ## [End] Sync Request template. **", - "Query.syncPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.syncPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", } `; -exports[`ModelTransformer: should generate sync resolver with ConflictHandlerType.OPTIMISTIC 1`] = ` +exports[`ModelTransformer: should generate sync resolver with ConflictHandlerType.Optimistic 1`] = ` Object { "Mutation.createAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) @@ -6680,6 +8492,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createAuthor.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -6764,13 +8582,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Author\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -6782,6 +8601,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createComment.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -6866,13 +8691,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Comment\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createEmail.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -6884,6 +8710,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createEmail.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -6968,13 +8800,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Email\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -6986,6 +8819,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -7070,13 +8909,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createRequire.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -7088,6 +8928,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createRequire.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -7172,13 +9018,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Require\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -7190,6 +9037,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createTest.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -7274,13 +9127,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -7292,6 +9146,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createUser.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -7376,13 +9236,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"User\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.customCreatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -7394,6 +9255,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.customCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customCreatePost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -7478,13 +9345,20 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.customCreatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customCreatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.customDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customDeletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -7542,13 +9416,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.customDeletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customDeletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.customUpdatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -7558,6 +9433,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.customUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.customUpdatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -7687,13 +9568,20 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.customUpdatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.customUpdatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteAuthor.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -7751,13 +9639,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteComment.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -7815,13 +9710,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteEmail.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -7879,13 +9781,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -7944,13 +9853,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) $util.qr($DeleteRequest.put(\\"_version\\", $util.defaultIfNull($ctx.args.input[\\"_version\\"], \\"0\\"))) $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteRequire.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -8008,13 +9924,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteTest.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -8072,13 +9995,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteUser.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -8136,13 +10066,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8152,6 +10083,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateAuthor.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -8281,13 +10218,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8297,6 +10235,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateComment.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -8426,13 +10370,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateEmail.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8442,6 +10387,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateEmail.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -8571,13 +10522,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateEmail.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8587,6 +10539,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -8717,13 +10675,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateRequire.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8733,6 +10692,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateRequire.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -8862,13 +10827,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateRequire.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -8878,6 +10844,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateTest.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -9007,13 +10979,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -9023,6 +10996,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateUser.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -9152,35 +11131,70 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.customGetPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.customGetPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.customGetPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.customGetPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.customListPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.customListPost.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9190,8 +11204,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9215,189 +11241,419 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.customListPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.customListPost.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getAuthor.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getAuthor.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getComment.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getComment.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getEmail.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getEmail.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getEmail.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getEntity.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getEntity.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getEntity.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getEntity.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getRequire.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getRequire.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getRequire.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getUser.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getUser.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.listAuthors.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listAuthors.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9407,8 +11663,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9432,13 +11700,19 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listAuthors.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listAuthors.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listComments.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listComments.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9448,8 +11722,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9473,13 +11759,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listComments.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listComments.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listEmails.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listEmails.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9489,8 +11781,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9514,13 +11818,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listEmails.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listEmails.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listPosts.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9530,8 +11840,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9555,13 +11877,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listRequires.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listRequires.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9571,8 +11899,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9596,13 +11936,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listRequires.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listRequires.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9612,8 +11958,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9637,13 +11995,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listUsers.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listUsers.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -9653,8 +12017,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -9678,19 +12054,46 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listUsers.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listUsers.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.syncPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.syncPosts.req.vtl": "## [Start] Sync Request template. ** +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end +#end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Sync\\", - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -9699,13 +12102,328 @@ null \\"nextToken\\": $util.toJson($util.defaultIfNull($ctx.args.nextToken, null)) } ## [End] Sync Request template. **", - "Query.syncPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.syncPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type, $ctx.result) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateEmail.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateEmail.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateEmail.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateRequire.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateRequire.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateRequire.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", } `; diff --git a/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts b/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts index 557b0565fb5..5c07bb2650a 100644 --- a/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts +++ b/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts @@ -881,7 +881,7 @@ describe('ModelTransformer: ', () => { validateModelSchema(parse(out.schema)); }); - it('should generate sync resolver with ConflictHandlerType.AUTOMERGE', () => { + it('should generate sync resolver with ConflictHandlerType.Automerge', () => { const validSchema = ` type Post @model { id: ID! @@ -913,7 +913,7 @@ describe('ModelTransformer: ', () => { validateModelSchema(parse(definition)); }); - it('should generate sync resolver with ConflictHandlerType.LAMBDA', () => { + it('should generate sync resolver with ConflictHandlerType.Lambda', () => { const validSchema = ` type Post @model { id: ID! @@ -950,7 +950,7 @@ describe('ModelTransformer: ', () => { validateModelSchema(parse(definition)); }); - it('should generate sync resolver with ConflictHandlerType.OPTIMISTIC', () => { + it('should generate sync resolver with ConflictHandlerType.Optimistic', () => { const validSchema = ` type Post @model { id: ID! @@ -984,6 +984,27 @@ describe('ModelTransformer: ', () => { validateModelSchema(parse(definition)); }); + it('should support sandbox mode of api', async () => { + const validSchema = ` + type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: "staging") + + type Post @model { + id: ID! + title: String! + } + `; + + const transformer = new GraphQLTransform({ + transformers: [new ModelTransformer()], + featureFlags, + }); + + const out = transformer.transform(validSchema); + expect(out).toBeDefined(); + + parse(out.schema); + }); + it('should generate iam role names under 64 chars and subscriptions under 50', () => { const validSchema = ` type ThisIsAVeryLongNameModelThatShouldNotGenerateIAMRoleNamesOver64Characters @model { diff --git a/packages/amplify-graphql-model-transformer/src/definitions.ts b/packages/amplify-graphql-model-transformer/src/definitions.ts index e1aafe51b0e..77d4eb31c58 100644 --- a/packages/amplify-graphql-model-transformer/src/definitions.ts +++ b/packages/amplify-graphql-model-transformer/src/definitions.ts @@ -13,4 +13,4 @@ export const BOOLEAN_FUNCTIONS = new Set(['attributeExists', 'attributeT export const ATTRIBUTE_TYPES = ['binary', 'binarySet', 'bool', 'list', 'map', 'number', 'numberSet', 'string', 'stringSet', '_null']; - +export const OPERATION_KEY = '__operation'; diff --git a/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts b/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts index 544ccc833f8..fc9bcddfda7 100644 --- a/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts +++ b/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts @@ -54,6 +54,7 @@ import { makeUpdateInputField, } from './graphql-types'; import { + generateAuthExpressionForSandboxMode, generateCreateInitSlotTemplate, generateCreateRequestTemplate, generateDefaultResponseMappingTemplate, @@ -64,7 +65,12 @@ import { generateUpdateInitSlotTemplate, generateUpdateRequestTemplate, } from './resolvers'; -import { generateGetRequestTemplate, generateListRequestTemplate, generateSyncRequestTemplate } from './resolvers/query'; +import { + generateGetRequestTemplate, + generateGetResponseTemplate, + generateListRequestTemplate, + generateSyncRequestTemplate, +} from './resolvers/query'; import { DirectiveWrapper, FieldWrapper, @@ -88,17 +94,17 @@ export type ModelDirectiveConfiguration = { list: OptionalAndNullable; sync: OptionalAndNullable; }>; - mutations: { + mutations: OptionalAndNullable<{ create: OptionalAndNullable; update: OptionalAndNullable; delete: OptionalAndNullable; - } | null; - subscriptions: { + }>; + subscriptions: OptionalAndNullable<{ onCreate: OptionalAndNullable[]; onUpdate: OptionalAndNullable[]; onDelete: OptionalAndNullable[]; - level: Partial; - } | null; + level: SubscriptionLevel; + }>; timestamps: OptionalAndNullable<{ createdAt: OptionalAndNullable; updatedAt: OptionalAndNullable; @@ -169,12 +175,13 @@ export class ModelTransformer extends TransformerModelBase implements Transforme `'${definition.name.value}' is a reserved type name and currently in use within the default schema element.`, ); } - // todo: get model configuration with default values and store it in the map const typeName = definition.name.value; + if (ctx.isProjectUsingDataStore()) { SyncUtils.validateResolverConfigForType(ctx, typeName); } + const directiveWrapped: DirectiveWrapper = new DirectiveWrapper(directive); const options = directiveWrapped.getArguments({ queries: { @@ -188,7 +195,7 @@ export class ModelTransformer extends TransformerModelBase implements Transforme delete: toCamelCase(['delete', typeName]), }, subscriptions: { - level: SubscriptionLevel.public, + level: SubscriptionLevel.on, onCreate: [this.ensureValidSubscriptionName(toCamelCase(['onCreate', typeName]))], onDelete: [this.ensureValidSubscriptionName(toCamelCase(['onDelete', typeName]))], onUpdate: [this.ensureValidSubscriptionName(toCamelCase(['onUpdate', typeName]))], @@ -234,6 +241,8 @@ export class ModelTransformer extends TransformerModelBase implements Transforme this.addAutoGeneratableFields(ctx, type); if (ctx.isProjectUsingDataStore()) { + SyncUtils.validateResolverConfigForType(ctx, def!.name.value); + this.options.SyncConfig = SyncUtils.getSyncConfig(ctx, def!.name.value); this.addModelSyncFields(ctx, type); } } @@ -241,8 +250,7 @@ export class ModelTransformer extends TransformerModelBase implements Transforme generateResolvers = (context: TransformerContextProvider): void => { for (let type of this.typesWithModelDirective) { - const def = context.output.getObject(type); - + const def = context.output.getObject(type)!; // This name is used by the mock functionality. Changing this can break mock. const tableLogicalName = `${def!.name.value}Table`; const stack = context.stackManager.getStackFor(tableLogicalName, def!.name.value); @@ -265,7 +273,13 @@ export class ModelTransformer extends TransformerModelBase implements Transforme default: throw new Error('Unknown query field type'); } - + resolver.addToSlot( + 'postAuth', + MappingTemplate.s3MappingTemplateFromString( + generateAuthExpressionForSandboxMode(context), + `${query.typeName}.${query.fieldName}.{slotName}.{slotIndex}.req.vtl`, + ), + ); resolver.mapToStack(stack); context.resolvers.addResolver(query.typeName, query.fieldName, resolver); } @@ -284,11 +298,49 @@ export class ModelTransformer extends TransformerModelBase implements Transforme resolver = this.generateUpdateResolver(context, def!, mutation.typeName, mutation.fieldName); break; default: - throw new Error('Unknown query field type'); + throw new Error('Unknown mutation field type'); } + resolver.addToSlot( + 'postAuth', + MappingTemplate.s3MappingTemplateFromString( + generateAuthExpressionForSandboxMode(context), + `${mutation.typeName}.${mutation.fieldName}.{slotName}.{slotIndex}.req.vtl`, + ), + ); resolver.mapToStack(stack); context.resolvers.addResolver(mutation.typeName, mutation.fieldName, resolver); } + + const subscriptionLevel = this.modelDirectiveConfig.get(def.name.value)?.subscriptions?.level; + // in order to create subscription resolvers the level needs to be on + if (subscriptionLevel === SubscriptionLevel.on) { + const subscriptionFields = this.getSubscriptionFieldNames(context, def!); + for (let subscription of subscriptionFields.values()) { + let resolver; + switch (subscription.type) { + case SubscriptionFieldType.ON_CREATE: + resolver = this.generateOnCreateResolver(context, def, subscription.typeName, subscription.fieldName); + break; + case SubscriptionFieldType.ON_UPDATE: + resolver = this.generateOnUpdateResolver(context, def, subscription.typeName, subscription.fieldName); + break; + case SubscriptionFieldType.ON_DELETE: + resolver = this.generateOnDeleteResolver(context, def, subscription.typeName, subscription.fieldName); + break; + default: + throw new Error('Unknown subscription field type'); + } + resolver.addToSlot( + 'postAuth', + MappingTemplate.s3MappingTemplateFromString( + generateAuthExpressionForSandboxMode(context), + `${subscription.typeName}.${subscription.fieldName}.{slotName}.{slotIndex}.req.vtl`, + ), + ); + resolver.mapToStack(stack); + context.resolvers.addResolver(subscription.typeName, subscription.fieldName, resolver); + } + } } }; @@ -307,10 +359,7 @@ export class ModelTransformer extends TransformerModelBase implements Transforme fieldName, dataSource, MappingTemplate.s3MappingTemplateFromString(generateGetRequestTemplate(), `${typeName}.${fieldName}.req.vtl`), - MappingTemplate.s3MappingTemplateFromString( - generateDefaultResponseMappingTemplate(isSyncEnabled), - `${typeName}.${fieldName}.res.vtl`, - ), + MappingTemplate.s3MappingTemplateFromString(generateGetResponseTemplate(isSyncEnabled), `${typeName}.${fieldName}.res.vtl`), ); } return this.resolverMap[resolverKey]; @@ -359,7 +408,7 @@ export class ModelTransformer extends TransformerModelBase implements Transforme `${typeName}.${fieldName}.req.vtl`, ), MappingTemplate.s3MappingTemplateFromString( - generateDefaultResponseMappingTemplate(isSyncEnabled), + generateDefaultResponseMappingTemplate(isSyncEnabled, true), `${typeName}.${fieldName}.res.vtl`, ), ); @@ -391,7 +440,7 @@ export class ModelTransformer extends TransformerModelBase implements Transforme dataSource, MappingTemplate.s3MappingTemplateFromString(generateDeleteRequestTemplate(isSyncEnabled), `${typeName}.${fieldName}.req.vtl`), MappingTemplate.s3MappingTemplateFromString( - generateDefaultResponseMappingTemplate(isSyncEnabled), + generateDefaultResponseMappingTemplate(isSyncEnabled, true), `${typeName}.${fieldName}.res.vtl`, ), ); @@ -701,7 +750,7 @@ export class ModelTransformer extends TransformerModelBase implements Transforme dataSource, MappingTemplate.s3MappingTemplateFromString(generateCreateRequestTemplate(type.name.value), `${typeName}.${fieldName}.req.vtl`), MappingTemplate.s3MappingTemplateFromString( - generateDefaultResponseMappingTemplate(isSyncEnabled), + generateDefaultResponseMappingTemplate(isSyncEnabled, true), `${typeName}.${fieldName}.res.vtl`, ), ); @@ -1158,13 +1207,15 @@ export class ModelTransformer extends TransformerModelBase implements Transforme }), ); - const syncConfig = SyncUtils.getSyncConfig(context, def!.name.value); - if (syncConfig && SyncUtils.isLambdaSyncConfig(syncConfig)) { + if (this.options.SyncConfig && SyncUtils.isLambdaSyncConfig(this.options.SyncConfig)) { role.attachInlinePolicy( - SyncUtils.createSyncLambdaIAMPolicy(stack, syncConfig.LambdaConflictHandler.name, syncConfig.LambdaConflictHandler.region), + SyncUtils.createSyncLambdaIAMPolicy( + stack, + this.options.SyncConfig.LambdaConflictHandler.name, + this.options.SyncConfig.LambdaConflictHandler.region, + ), ); } - return role; } diff --git a/packages/amplify-graphql-model-transformer/src/index.ts b/packages/amplify-graphql-model-transformer/src/index.ts index d419f3ed214..10267d40d30 100644 --- a/packages/amplify-graphql-model-transformer/src/index.ts +++ b/packages/amplify-graphql-model-transformer/src/index.ts @@ -1,3 +1,4 @@ -export { ModelTransformer } from './graphql-model-transformer'; +export { ModelTransformer, ModelDirectiveConfiguration, SubscriptionLevel } from './graphql-model-transformer'; +export { OPERATION_KEY } from './definitions'; export * from './graphql-types'; export * from './resolvers'; diff --git a/packages/amplify-graphql-model-transformer/src/resolvers/common.ts b/packages/amplify-graphql-model-transformer/src/resolvers/common.ts index ed2fcd07e41..3d3c367f43a 100644 --- a/packages/amplify-graphql-model-transformer/src/resolvers/common.ts +++ b/packages/amplify-graphql-model-transformer/src/resolvers/common.ts @@ -15,7 +15,13 @@ import { ifElse, printBlock, toJson, + qref, + str, + not, } from 'graphql-mapping-template'; +import { OPERATION_KEY } from '../definitions'; + +const API_KEY = 'API Key Authorization'; /** * Helper method to generate code that converts DynamoDB condition object to condition @@ -57,9 +63,11 @@ export const generateConditionSlot = (inputConditionObjectName: string, conditio /** * Generate common response template used by most of the resolvers. + * Append operation if response is coming from a mutation, this is to protect field resolver for subscriptions */ -export const generateDefaultResponseMappingTemplate = (isSyncEnabled: boolean): string => { +export const generateDefaultResponseMappingTemplate = (isSyncEnabled: boolean, mutation = false): string => { const statements: Expression[] = []; + if (mutation) statements.push(qref(methodCall(ref('ctx.result.put'), str(OPERATION_KEY), str('Mutation')))); if (isSyncEnabled) { statements.push( ifElse( @@ -74,14 +82,30 @@ export const generateDefaultResponseMappingTemplate = (isSyncEnabled: boolean): ); } - return printBlock('Get ResponseTemplate')(compoundExpression(statements)); + return printBlock('ResponseTemplate')(compoundExpression(statements)); }; /** - * Util function to gernate resolver key used to keep track of all the resolvers in memory + * Util function to generate resolver key used to keep track of all the resolvers in memory * @param typeName Name of the type * @param fieldName Name of the field */ export const generateResolverKey = (typeName: string, fieldName: string): string => { return `${typeName}.${fieldName}`; }; + +/** + * Util function to generate sandbox mode expression + * @param ctx context to get sandbox mode + */ +export const generateAuthExpressionForSandboxMode = (ctx: any): string => { + let enabled = ctx.resourceHelper.api.globalSandboxModeEnabled; + let exp; + + if (enabled) exp = iff(notEquals(methodCall(ref('util.authType')), str(API_KEY)), methodCall(ref('util.unauthorized'))); + else exp = methodCall(ref('util.unauthorized')); + + return printBlock(`Sandbox Mode ${enabled ? 'Enabled' : 'Disabled'}`)( + compoundExpression([iff(not(ref('ctx.stash.get("hasAuth")')), exp), toJson(obj({}))]), + ); +}; diff --git a/packages/amplify-graphql-model-transformer/src/resolvers/query.ts b/packages/amplify-graphql-model-transformer/src/resolvers/query.ts index d73bfb587be..2e9c86ead13 100644 --- a/packages/amplify-graphql-model-transformer/src/resolvers/query.ts +++ b/packages/amplify-graphql-model-transformer/src/resolvers/query.ts @@ -16,27 +16,81 @@ import { equals, bool, and, + isNullOrEmpty, + list, + forEach, nul, } from 'graphql-mapping-template'; import { ResourceConstants } from 'graphql-transformer-common'; +const authFilter = ref('ctx.stash.authFilter'); + /** * Generate get query resolver template */ export const generateGetRequestTemplate = (): string => { const statements: Expression[] = [ - set(ref('GetRequest'), obj({ version: str('2018-05-29'), operation: str('GetItem') })), + set(ref('GetRequest'), obj({ version: str('2018-05-29'), operation: str('Query') })), ifElse( ref('ctx.stash.metadata.modelObjectKey'), - set(ref('key'), ref('ctx.stash.metadata.modelObjectKey')), - compoundExpression([set(ref('key'), obj({ id: methodCall(ref('util.dynamodb.toDynamoDB'), ref('ctx.args.id')) }))]), + compoundExpression([ + set(ref('expression'), str('')), + set(ref('expressionValues'), obj({})), + forEach(ref('item'), ref('ctx.stash.metadata.modelObjectKey.entrySet()'), [ + set(ref('expression'), str('$expression$item.key = :$item.key AND ')), + qref(methodCall(ref('expressionValues.put'), str(':$item.key'), ref('item.value'))), + ]), + set(ref('expression'), methodCall(ref('expression.replaceAll'), str('AND $'), str(''))), + set(ref('query'), obj({ expression: ref('expression'), expressionValues: ref('expressionValues') })), + ]), + set( + ref('query'), + obj({ + expression: str('id = :id'), + expressionValues: obj({ + ':id': methodCall(ref('util.parseJson'), methodCall(ref('util.dynamodb.toDynamoDBJson'), ref('ctx.args.id'))), + }), + }), + ), + ), + qref(methodCall(ref('GetRequest.put'), str('query'), ref('query'))), + iff( + not(isNullOrEmpty(authFilter)), + qref( + methodCall( + ref('GetRequest.put'), + str('filter'), + methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), authFilter)), + ), + ), ), - qref(methodCall(ref('GetRequest.put'), str('key'), ref('key'))), toJson(ref('GetRequest')), ]; return printBlock('Get Request template')(compoundExpression(statements)); }; +export const generateGetResponseTemplate = (isSyncEnabled: boolean): string => { + const statements = new Array(); + if (isSyncEnabled) { + statements.push( + iff(ref('ctx.error'), methodCall(ref('util.error'), ref('ctx.error.message'), ref('ctx.error.type'), ref('ctx.result'))), + ); + } else { + statements.push(iff(ref('ctx.error'), methodCall(ref('util.error'), ref('ctx.error.message'), ref('ctx.error.type')))); + } + statements.push( + ifElse( + and([not(ref('ctx.result.items.isEmpty()')), equals(ref('ctx.result.scannedCount'), int(1))]), + toJson(ref('ctx.result.items[0]')), + compoundExpression([ + iff(and([ref('ctx.result.items.isEmpty()'), equals(ref('ctx.result.scannedCount'), int(1))]), ref('util.unauthorized()')), + toJson(nul()), + ]), + ), + ); + return printBlock('Get Response template')(compoundExpression(statements)); +}; + export const generateListRequestTemplate = (): string => { const requestVariable = 'ListRequest'; const modelQueryObj = 'ctx.stash.modelQueryExpression'; @@ -51,12 +105,20 @@ export const generateListRequestTemplate = (): string => { }), ), iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken'))), + ifElse( + not(isNullOrEmpty(authFilter)), + compoundExpression([ + set(ref('filter'), authFilter), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), obj({ and: list([ref('filter'), ref('ctx.args.filter')]) }))), + ]), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), ref('ctx.args.filter'))), + ), iff( - ref('context.args.filter'), + not(isNullOrEmpty(ref('filter'))), compoundExpression([ set( ref(`filterExpression`), - methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), ref('ctx.args.filter'))), + methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), ref('filter'))), ), iff( not(methodCall(ref('util.isNullOrBlank'), ref('filterExpression.expression'))), @@ -95,10 +157,37 @@ export const generateListRequestTemplate = (): string => { export const generateSyncRequestTemplate = (): string => { return printBlock('Sync Request template')( compoundExpression([ + ifElse( + not(isNullOrEmpty(authFilter)), + compoundExpression([ + set(ref('filter'), authFilter), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), obj({ and: list([ref('filter'), ref('ctx.args.filter')]) }))), + ]), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), ref('ctx.args.filter'))), + ), + iff( + not(isNullOrEmpty(ref('filter'))), + compoundExpression([ + set( + ref(`filterExpression`), + methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), ref('filter'))), + ), + iff( + not(methodCall(ref('util.isNullOrBlank'), ref('filterExpression.expression'))), + compoundExpression([ + iff( + equals(methodCall(ref('filterEpression.expressionValues.size')), int(0)), + qref(methodCall(ref('filterEpression.remove'), str('expressionValues'))), + ), + set(ref('filter'), ref('filterExpression')), + ]), + ), + ]), + ), obj({ version: str('2018-05-29'), operation: str('Sync'), - filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()), + filter: ifElse(ref('filter'), ref('util.toJson($filter)'), nul()), limit: ref(`util.defaultIfNull($ctx.args.limit, ${ResourceConstants.DEFAULT_SYNC_QUERY_PAGE_LIMIT})`), lastSync: ref('util.toJson($util.defaultIfNull($ctx.args.lastSync, null))'), nextToken: ref('util.toJson($util.defaultIfNull($ctx.args.nextToken, null))'), diff --git a/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts b/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts index bd3b5eb2885..db57b7e0e75 100644 --- a/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts +++ b/packages/amplify-graphql-predictions-transformer/src/graphql-predictions-transformer.ts @@ -1,5 +1,12 @@ import * as path from 'path'; -import { DirectiveWrapper, InvalidDirectiveError, MappingTemplate, TransformerPluginBase } from '@aws-amplify/graphql-transformer-core'; +import { + DirectiveWrapper, + IAM_AUTH_ROLE_PARAMETER, + IAM_UNAUTH_ROLE_PARAMETER, + InvalidDirectiveError, + MappingTemplate, + TransformerPluginBase, +} from '@aws-amplify/graphql-transformer-core'; import { TransformerContextProvider, TransformerSchemaVisitStepContextProvider, @@ -50,6 +57,7 @@ import { translateTextAmzTarget, PREDICTIONS_DIRECTIVE_STACK, } from './utils/constants'; +import { AuthorizationType } from '@aws-cdk/aws-appsync'; type PredictionsDirectiveConfiguration = { actions: string[] | undefined; @@ -91,7 +99,7 @@ export class PredictionsTransformer extends TransformerPluginBase { } as PredictionsDirectiveConfiguration); if (!Array.isArray(args.actions)) { - args.actions = [(args.actions as unknown) as string]; + args.actions = [args.actions as unknown as string]; } validateActions(args.actions); @@ -318,23 +326,50 @@ function createResolver( if (referencesEnv(bucketName)) { const env = context.stackManager.getParameter(ResourceConstants.PARAMETERS.Env) as cdk.CfnParameter; - substitutions.env = (env as unknown) as string; + substitutions.env = env as unknown as string; + } + const requestTemplate = [ + cdk.Fn.conditionIf( + ResourceConstants.CONDITIONS.HasEnvironmentParameter, + cdk.Fn.sub(`$util.qr($ctx.stash.put("s3Bucket", "${bucketName}"))`, substitutions), + cdk.Fn.sub(`$util.qr($ctx.stash.put("s3Bucket", "${removeEnvReference(bucketName)}"))`, { + hash: cdk.Fn.select(3, cdk.Fn.split('-', cdk.Fn.ref('AWS::StackName'))), + }), + ) as unknown as string, + print(compoundExpression([qref('$ctx.stash.put("isList", false)')])), + ]; + // TODO: predictions should use resolver manager + const authModes = [context.authConfig.defaultAuthentication, ...(context.authConfig.additionalAuthenticationProviders || [])].map( + mode => mode?.authenticationType, + ); + if (authModes.includes(AuthorizationType.IAM)) { + const authRoleParameter = (context.stackManager.getParameter(IAM_AUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString; + const unauthRoleParameter = (context.stackManager.getParameter(IAM_UNAUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString; + requestTemplate.push( + `$util.qr($ctx.stash.put("authRole", "arn:aws:sts::${ + cdk.Stack.of(context.stackManager.rootStack).account + }:assumed-role/${authRoleParameter}/CognitoIdentityCredentials"))`, + `$util.qr($ctx.stash.put("unauthRole", "arn:aws:sts::${ + cdk.Stack.of(context.stackManager.rootStack).account + }:assumed-role/${unauthRoleParameter}/CognitoIdentityCredentials"))`, + ); } + requestTemplate.push(print(obj({}))); return context.api.host.addResolver( config.resolverTypeName, config.resolverFieldName, MappingTemplate.inlineTemplateFromString( - (cdk.Fn.join('\n', [ - (cdk.Fn.conditionIf( + cdk.Fn.join('\n', [ + cdk.Fn.conditionIf( ResourceConstants.CONDITIONS.HasEnvironmentParameter, cdk.Fn.sub(`$util.qr($ctx.stash.put("s3Bucket", "${bucketName}"))`, substitutions), cdk.Fn.sub(`$util.qr($ctx.stash.put("s3Bucket", "${removeEnvReference(bucketName)}"))`, { hash: cdk.Fn.select(3, cdk.Fn.split('-', cdk.Fn.ref('AWS::StackName'))), }), - ) as unknown) as string, + ) as unknown as string, print(compoundExpression([qref('$ctx.stash.put("isList", false)'), obj({})])), - ]) as unknown) as string, + ]) as unknown as string, ), MappingTemplate.inlineTemplateFromString( print( @@ -398,11 +433,11 @@ function removeEnvReference(value: string): string { function joinWithEnv(context: TransformerContextProvider, separator: string, listToJoin: any[]): string { const env = context.stackManager.getParameter(ResourceConstants.PARAMETERS.Env) as cdk.CfnParameter; - return (cdk.Fn.conditionIf( + return cdk.Fn.conditionIf( ResourceConstants.CONDITIONS.HasEnvironmentParameter, cdk.Fn.join(separator, [...listToJoin, env]), cdk.Fn.join(separator, listToJoin), - ) as unknown) as string; + ) as unknown as string; } function needsList(action: string, isCurrentlyList: boolean): boolean { @@ -500,14 +535,14 @@ function getStorageArn(context: TransformerContextProvider, bucketName: string): if (referencesEnv(bucketName)) { const env = context.stackManager.getParameter(ResourceConstants.PARAMETERS.Env) as cdk.CfnParameter; - substitutions.env = (env as unknown) as string; + substitutions.env = env as unknown as string; } - return (cdk.Fn.conditionIf( + return cdk.Fn.conditionIf( ResourceConstants.CONDITIONS.HasEnvironmentParameter, cdk.Fn.sub(s3ArnKey(bucketName), substitutions), cdk.Fn.sub(s3ArnKey(removeEnvReference(bucketName)), { hash: cdk.Fn.select(3, cdk.Fn.split('-', cdk.Fn.ref('AWS::StackName'))) }), - ) as unknown) as string; + ) as unknown as string; } function createActionFunction(context: TransformerContextProvider, stack: cdk.Stack, action: string, datasourceName: string) { diff --git a/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-has-many-transformer.test.ts.snap b/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-has-many-transformer.test.ts.snap index d06564b1739..bbb27712477 100644 --- a/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-has-many-transformer.test.ts.snap +++ b/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-has-many-transformer.test.ts.snap @@ -7639,7 +7639,7 @@ Object { "directives": Array [], "kind": "FieldDefinition", "loc": Object { - "end": 5275, + "end": 5260, "start": 5241, }, "name": Object { @@ -7653,22 +7653,22 @@ Object { "type": Object { "kind": "ListType", "loc": Object { - "end": 5275, + "end": 5260, "start": 5248, }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5274, + "end": 5259, "start": 5249, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5274, + "end": 5259, "start": 5249, }, - "value": "ModelPostEditorConnection", + "value": "PostEditor", }, }, }, @@ -7679,28 +7679,28 @@ Object { "directives": Array [], "kind": "FieldDefinition", "loc": Object { - "end": 5295, - "start": 5278, + "end": 5280, + "start": 5263, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5287, - "start": 5278, + "end": 5272, + "start": 5263, }, "value": "nextToken", }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5295, - "start": 5289, + "end": 5280, + "start": 5274, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5295, - "start": 5289, + "end": 5280, + "start": 5274, }, "value": "String", }, @@ -7710,7 +7710,7 @@ Object { "interfaces": Array [], "kind": "ObjectTypeDefinition", "loc": Object { - "end": 5297, + "end": 5282, "start": 5206, }, "name": Object { @@ -7732,28 +7732,28 @@ Object { "directives": Array [], "kind": "InputValueDefinition", "loc": Object { - "end": 5352, - "start": 5336, + "end": 5337, + "start": 5321, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5338, - "start": 5336, + "end": 5323, + "start": 5321, }, "value": "id", }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5352, - "start": 5340, + "end": 5337, + "start": 5325, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5352, - "start": 5340, + "end": 5337, + "start": 5325, }, "value": "ModelIDInput", }, @@ -7765,28 +7765,28 @@ Object { "directives": Array [], "kind": "InputValueDefinition", "loc": Object { - "end": 5375, - "start": 5355, + "end": 5360, + "start": 5340, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5361, - "start": 5355, + "end": 5346, + "start": 5340, }, "value": "postID", }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5375, - "start": 5363, + "end": 5360, + "start": 5348, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5375, - "start": 5363, + "end": 5360, + "start": 5348, }, "value": "ModelIDInput", }, @@ -7798,28 +7798,28 @@ Object { "directives": Array [], "kind": "InputValueDefinition", "loc": Object { - "end": 5400, - "start": 5378, + "end": 5385, + "start": 5363, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5386, - "start": 5378, + "end": 5371, + "start": 5363, }, "value": "editorID", }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5400, - "start": 5388, + "end": 5385, + "start": 5373, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5400, - "start": 5388, + "end": 5385, + "start": 5373, }, "value": "ModelIDInput", }, @@ -7831,34 +7831,34 @@ Object { "directives": Array [], "kind": "InputValueDefinition", "loc": Object { - "end": 5436, - "start": 5403, + "end": 5421, + "start": 5388, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5406, - "start": 5403, + "end": 5391, + "start": 5388, }, "value": "and", }, "type": Object { "kind": "ListType", "loc": Object { - "end": 5436, - "start": 5408, + "end": 5421, + "start": 5393, }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5435, - "start": 5409, + "end": 5420, + "start": 5394, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5435, - "start": 5409, + "end": 5420, + "start": 5394, }, "value": "ModelPostEditorFilterInput", }, @@ -7871,34 +7871,34 @@ Object { "directives": Array [], "kind": "InputValueDefinition", "loc": Object { - "end": 5471, - "start": 5439, + "end": 5456, + "start": 5424, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5441, - "start": 5439, + "end": 5426, + "start": 5424, }, "value": "or", }, "type": Object { "kind": "ListType", "loc": Object { - "end": 5471, - "start": 5443, + "end": 5456, + "start": 5428, }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5470, - "start": 5444, + "end": 5455, + "start": 5429, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5470, - "start": 5444, + "end": 5455, + "start": 5429, }, "value": "ModelPostEditorFilterInput", }, @@ -7911,28 +7911,28 @@ Object { "directives": Array [], "kind": "InputValueDefinition", "loc": Object { - "end": 5505, - "start": 5474, + "end": 5490, + "start": 5459, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5477, - "start": 5474, + "end": 5462, + "start": 5459, }, "value": "not", }, "type": Object { "kind": "NamedType", "loc": Object { - "end": 5505, - "start": 5479, + "end": 5490, + "start": 5464, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5505, - "start": 5479, + "end": 5490, + "start": 5464, }, "value": "ModelPostEditorFilterInput", }, @@ -7941,14 +7941,14 @@ Object { ], "kind": "InputObjectTypeDefinition", "loc": Object { - "end": 5507, - "start": 5299, + "end": 5492, + "start": 5284, }, "name": Object { "kind": "Name", "loc": Object { - "end": 5331, - "start": 5305, + "end": 5316, + "start": 5290, }, "value": "ModelPostEditorFilterInput", }, @@ -7956,7 +7956,7 @@ Object { ], "kind": "Document", "loc": Object { - "end": 5509, + "end": 5494, "start": 0, }, } @@ -8018,6 +8018,27 @@ Object { $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.childName.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -8031,8 +8052,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -8130,6 +8151,27 @@ $util.error($ctx.error.message, $ctx.error.type) ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -8143,8 +8185,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -8175,7 +8217,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createChild.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createChild.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8271,13 +8319,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Child\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createChild.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createChild.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8289,6 +8338,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createComment.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8373,13 +8428,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Comment\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createFriendship.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8391,6 +8447,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createFriendship.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8475,13 +8537,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Friendship\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createFriendship.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createFriendship.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createParent.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8493,6 +8556,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createParent.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8577,13 +8646,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Parent\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createParent.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createParent.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8595,7 +8665,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createPost.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createPost.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -8690,13 +8766,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPostAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8708,6 +8785,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPostAuthor.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8792,13 +8875,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"PostAuthor\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPostAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPostAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPostEditor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8810,6 +8894,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPostEditor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPostEditor.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8894,13 +8984,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"PostEditor\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPostEditor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPostEditor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createPostModel.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -8912,6 +9003,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPostModel.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -8996,13 +9093,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"PostModel\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPostModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPostModel.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -9014,6 +9112,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createTest.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -9098,13 +9202,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createTest1.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -9116,7 +9221,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createTest1.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createTest1.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9219,13 +9330,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Test1\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createTest1.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createTest1.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -9237,7 +9349,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createUser.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createUser.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9340,13 +9458,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"User\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createUserModel.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -9358,7 +9477,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.createUserModel.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.createUserModel.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9370,7 +9495,7 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { ## [End] Set the primary key. ** {}", - "Mutation.createUserModel.postAuth.2.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.createUserModel.preAuth.2.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9481,14 +9606,21 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"UserModel\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createUserModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createUserModel.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteChild.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteChild.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9556,13 +9688,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteChild.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteChild.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteComment.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -9620,13 +9759,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteFriendship.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -9684,13 +9830,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteFriendship.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteFriendship.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteParent.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -9748,14 +9901,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteParent.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteParent.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deletePost.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deletePost.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -9822,13 +9982,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePostAuthor.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -9886,13 +10053,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePostAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePostAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePostEditor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePostEditor.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -9950,13 +10124,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePostEditor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePostEditor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePostModel.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -10014,13 +10195,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePostModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePostModel.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteTest.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -10078,14 +10266,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteTest1.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteTest1.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -10153,14 +10348,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteTest1.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteTest1.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteUser.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteUser.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -10228,14 +10430,21 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Mutation.deleteUserModel.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** +## [End] ResponseTemplate. **", + "Mutation.deleteUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.deleteUserModel.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -10246,7 +10455,7 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { })) ## [End] Set the primary key. ** {}", - "Mutation.deleteUserModel.postAuth.2.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.deleteUserModel.preAuth.2.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -10316,13 +10525,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteUserModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteUserModel.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateChild.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -10332,7 +10542,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateChild.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateChild.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -10473,13 +10689,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateChild.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateChild.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateComment.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -10489,6 +10706,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateComment.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -10618,13 +10841,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateComment.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateFriendship.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -10634,6 +10858,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateFriendship.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -10763,13 +10993,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateFriendship.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateFriendship.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateParent.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -10779,6 +11010,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateParent.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -10908,13 +11145,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateParent.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateParent.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -10924,7 +11162,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updatePost.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updatePost.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -11064,13 +11308,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePostAuthor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11080,6 +11325,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePostAuthor.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -11209,13 +11460,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePostAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePostAuthor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePostEditor.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11225,6 +11477,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePostEditor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePostEditor.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -11354,13 +11612,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePostEditor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePostEditor.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePostModel.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11370,6 +11629,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePostModel.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -11499,13 +11764,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePostModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePostModel.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11515,6 +11781,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateTest.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -11644,13 +11916,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateTest1.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11660,7 +11933,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateTest1.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateTest1.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -11808,13 +12087,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateTest1.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateTest1.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateUser.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11824,7 +12104,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateUser.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateUser.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -11972,13 +12258,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateUser.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateUserModel.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -11988,7 +12275,13 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", - "Mutation.updateUserModel.postAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Mutation.updateUserModel.preAuth.1.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -12000,7 +12293,7 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { ## [End] Set the primary key. ** {}", - "Mutation.updateUserModel.postAuth.2.req.vtl": "## [Start] Merge default values and inputs. ** + "Mutation.updateUserModel.preAuth.2.req.vtl": "## [Start] Merge default values and inputs. ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) $util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) ## [End] Merge default values and inputs. ** @@ -12156,45 +12449,74 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateUserModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateUserModel.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Parent.child.req.vtl": "#if( $util.isNull($ctx.source.childID) || $util.isNull($ctx.source.childName) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.childID, \\"___xamznone____\\")), - \\"name\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.childName, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id AND name = :name\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.childID, \\"___xamznone____\\"))), + \\":name\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.childName, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "Parent.child.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "Post.author.req.vtl": "#if( $util.isNull($ctx.source.owner) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.owner, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.owner, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "Post.author.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "Post.authors.req.vtl": "#if( $util.isNull($ctx.source.authorID) ) #set( $result = { @@ -12273,6 +12595,27 @@ $util.toJson($ctx.result) ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -12286,8 +12629,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -12323,6 +12666,27 @@ $util.error($ctx.error.message, $ctx.error.type) \\":partitionKey\\": $util.dynamodb.toDynamoDB($context.source.id) } } ) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -12336,8 +12700,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -12412,6 +12776,27 @@ $util.error($ctx.error.message, $ctx.error.type) $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.editorID.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -12425,8 +12810,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -12450,50 +12835,92 @@ $util.error($ctx.error.message, $ctx.error.type) "PostAuthor.post.req.vtl": "#if( $util.isNull($ctx.source.postID) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.postID, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.postID, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "PostAuthor.post.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "PostEditor.editor.req.vtl": "#if( $util.isNull($ctx.source.editorID) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.editorID, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.editorID, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "PostEditor.editor.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "PostEditor.post.req.vtl": "#if( $util.isNull($ctx.source.postID) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.postID, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.postID, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "PostEditor.post.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "PostModel.authors.req.vtl": "#if( $util.isNull($ctx.source.authorID) ) #set( $result = { @@ -12513,6 +12940,27 @@ $util.toJson($ctx.result) \\":sortKey\\": $util.dynamodb.toDynamoDB(\\"\${context.source.authorName}#\${context.source.authorSurname}\\") } } ) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -12526,8 +12974,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -12551,21 +12999,41 @@ $util.error($ctx.error.message, $ctx.error.type) "PostModel.singleAuthor.req.vtl": "#if( $util.isNull($ctx.source.authorID) || $util.isNull($ctx.source.authorName) || $util.isNull($ctx.source.authorSurname) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.authorID, \\"___xamznone____\\")), - \\"name#surname\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank(\\"\${ctx.source.authorName}#\${ctx.source.authorSurname}\\", \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id AND name#surname = :name#surname\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.authorID, \\"___xamznone____\\"))), + \\":name#surname\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank(\\"\${ctx.source.authorName}#\${ctx.source.authorSurname}\\", \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "PostModel.singleAuthor.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", - "Query.getChild.postAuth.1.req.vtl": "## [Start] Set the primary key. ** + "Query.getChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getChild.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id), \\"name\\": $util.dynamodb.toDynamoDB($ctx.args.name) @@ -12575,92 +13043,204 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getChild.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getChild.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getChild.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getComment.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getComment.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getComment.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getFriendship.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getFriendship.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getFriendship.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getParent.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getParent.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getParent.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.getPost.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] Get Response template. **", + "Query.getPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getPost.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"title\\": $util.dynamodb.toDynamoDB($ctx.args.title) })) @@ -12669,92 +13249,204 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getPostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getPostAuthor.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPostAuthor.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPostAuthor.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getPostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getPostModel.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPostModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPostModel.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getTest.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.getTest1.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +## [End] Get Response template. **", + "Query.getTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getTest1.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id), \\"email#name\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.email}#\${ctx.args.name}\\") @@ -12764,26 +13456,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getTest1.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getTest1.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getTest1.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", - "Query.getUser.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getUser.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id), \\"name#surname\\": $util.dynamodb.toDynamoDB(\\"\${ctx.args.name}#\${ctx.args.surname}\\") @@ -12793,26 +13513,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getUser.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getUser.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getUser.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", - "Query.getUserModel.postAuth.1.req.vtl": "## [Start] Set the primary key. ** +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.getUserModel.preAuth.1.req.vtl": "## [Start] Set the primary key. ** $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id), \\"rollNumber\\": $util.dynamodb.toDynamoDB($ctx.args.rollNumber) @@ -12822,26 +13570,54 @@ $util.qr($ctx.stash.metadata.put(\\"modelObjectKey\\", { "Query.getUserModel.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getUserModel.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getUserModel.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", - "Query.listChildren.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] Get Response template. **", + "Query.listChildren.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listChildren.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") #end @@ -12912,8 +13688,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -12937,13 +13725,19 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listChildren.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listChildren.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listComments.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listComments.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -12953,8 +13747,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -12978,13 +13784,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listComments.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listComments.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listFriendships.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listFriendships.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -12994,8 +13806,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13019,13 +13843,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listFriendships.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listFriendships.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listParents.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listParents.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -13035,8 +13865,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13060,13 +13902,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listParents.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listParents.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listPostAuthors.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listPostAuthors.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -13076,8 +13924,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13101,13 +13961,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPostAuthors.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPostAuthors.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listPostModels.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listPostModels.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -13117,8 +13983,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13142,14 +14020,20 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPostModels.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPostModels.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.listPosts.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] ResponseTemplate. **", + "Query.listPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listPosts.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"sortDirection is not supported for List operations without a Sort key defined.\\", \\"InvalidArgumentsError\\") #end @@ -13177,8 +14061,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13202,14 +14098,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.listTest1s.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] ResponseTemplate. **", + "Query.listTest1s.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listTest1s.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") #end @@ -13326,8 +14228,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13351,13 +14265,19 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTest1s.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTest1s.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listTests.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listTests.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -13367,8 +14287,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13392,14 +14324,20 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listTests.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listTests.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.listUserModels.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] ResponseTemplate. **", + "Query.listUserModels.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listUserModels.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") #end @@ -13470,8 +14408,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13495,14 +14445,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listUserModels.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listUserModels.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", - "Query.listUsers.postAuth.1.req.vtl": "## [Start] Set query expression for key ** +## [End] ResponseTemplate. **", + "Query.listUsers.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Query.listUsers.preAuth.1.req.vtl": "## [Start] Set query expression for key ** #if( $util.isNull($ctx.args.id) && !$util.isNull($ctx.args.sortDirection) ) $util.error(\\"When providing argument 'sortDirection' you must also provide argument 'id'.\\", \\"InvalidArgumentsError\\") #end @@ -13619,8 +14575,20 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -13644,13 +14612,553 @@ $util.qr($ctx.stash.put(\\"modelQueryExpression\\", $modelQueryExpression)) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listUsers.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listUsers.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateChild.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateChild.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateFriendship.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateFriendship.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateParent.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateParent.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePostAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePostAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePostEditor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePostEditor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePostEditor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreatePostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePostModel.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePostModel.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateTest1.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateTest1.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateUserModel.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateUserModel.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteChild.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteChild.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteFriendship.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteFriendship.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteParent.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteParent.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePostAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePostAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePostEditor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePostEditor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePostEditor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePostModel.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePostModel.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteTest1.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteTest1.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteUserModel.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteUserModel.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateChild.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateChild.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateChild.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateComment.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateComment.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateComment.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateFriendship.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateFriendship.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateFriendship.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateParent.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateParent.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateParent.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePostAuthor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePostAuthor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePostAuthor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePostEditor.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePostEditor.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePostEditor.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePostModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePostModel.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePostModel.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateTest.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateTest1.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateTest1.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateTest1.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateUser.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateUser.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateUser.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateUserModel.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateUserModel.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateUserModel.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", "Test.otherParts.req.vtl": "#if( $util.isNull($ctx.source.id) ) #set( $result = { \\"items\\": [] @@ -13728,6 +15236,27 @@ $util.toJson($ListRequest) ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -13741,8 +15270,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -13839,6 +15368,27 @@ $util.error($ctx.error.message, $ctx.error.type) ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -13852,8 +15402,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -13928,6 +15478,27 @@ $util.error($ctx.error.message, $ctx.error.type) $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.friendID.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -13941,8 +15512,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -14017,6 +15588,27 @@ $util.error($ctx.error.message, $ctx.error.type) $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.postID.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -14030,8 +15622,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -14106,6 +15698,27 @@ $util.error($ctx.error.message, $ctx.error.type) $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.postID.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -14119,8 +15732,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, diff --git a/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-many-to-many-transformer.test.ts.snap b/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-many-to-many-transformer.test.ts.snap index 3e58971d8e4..97868fefb2d 100644 --- a/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-many-to-many-transformer.test.ts.snap +++ b/packages/amplify-graphql-relational-transformer/src/__tests__/__snapshots__/amplify-graphql-many-to-many-transformer.test.ts.snap @@ -317,6 +317,27 @@ Object { $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.fooID.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -330,8 +351,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -406,6 +427,27 @@ $util.error($ctx.error.message, $ctx.error.type) $util.qr($query.expressionValues.put(\\":sortKey\\", { \\"S\\": \\"$ctx.args.barID.ge\\" })) #end ## [End] Applying Key Condition ** + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end + #else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end + #end + #if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) + #if( !$util.isNullOrBlank($filterExpression.expression) ) + #if( $filterEpression.expressionValues.size() == 0 ) + $util.qr($filterEpression.remove(\\"expressionValues\\")) + #end + #set( $filter = $filterExpression ) + #end + #end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"Query\\", @@ -419,8 +461,8 @@ false #else true #end, - \\"filter\\": #if( $context.args.filter ) -$util.transform.toDynamoDBFilterExpression($ctx.args.filter) + \\"filter\\": #if( $filter ) +$util.toJson($filter) #else null #end, @@ -444,34 +486,62 @@ $util.error($ctx.error.message, $ctx.error.type) "FooBar.bar.req.vtl": "#if( $util.isNull($ctx.source.barID) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.barID, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.barID, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "FooBar.bar.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "FooBar.foo.req.vtl": "#if( $util.isNull($ctx.source.fooID) ) #return #else -{ - \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\", - \\"key\\": { - \\"id\\": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.fooID, \\"___xamznone____\\")) - } + #set( $GetRequest = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"Query\\" +} ) + $util.qr($GetRequest.put(\\"query\\", { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.fooID, \\"___xamznone____\\"))) } +})) + #if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) + #end + $util.toJson($GetRequest) #end", "FooBar.foo.res.vtl": "#if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else -$util.toJson($ctx.result) + #if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) + #else + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) + #end #end", "Mutation.createBar.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) @@ -484,6 +554,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createBar.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -568,13 +644,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Bar\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createBar.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createFoo.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -586,6 +663,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createFoo.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -670,13 +753,14 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Foo\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createFoo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createFoo.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.createFooBar.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $createdAt = $util.time.nowISO8601() ) @@ -688,6 +772,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createFooBar.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -772,13 +862,20 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"FooBar\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createFooBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createFooBar.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteBar.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -836,13 +933,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteBar.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteFoo.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -900,13 +1004,20 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteFoo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteFoo.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deleteFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deleteFooBar.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -964,13 +1075,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deleteFooBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deleteFooBar.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateBar.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -980,6 +1092,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateBar.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -1109,13 +1227,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateBar.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateFoo.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -1125,6 +1244,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateFoo.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -1254,13 +1379,14 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateFoo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateFoo.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updateFooBar.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -1270,6 +1396,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updateFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updateFooBar.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -1399,79 +1531,170 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updateFooBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updateFooBar.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getBar.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getBar.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) +#end +## [End] Get Response template. **", + "Query.getFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() #end -## [End] Get ResponseTemplate. **", +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getFoo.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getFoo.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getFoo.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.getFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getFooBar.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getFooBar.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getFooBar.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.listBars.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listBars.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -1481,8 +1704,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1506,13 +1741,19 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listBars.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listBars.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listFooBars.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listFooBars.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -1522,8 +1763,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1547,13 +1800,19 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listFooBars.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listFooBars.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.listFoos.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listFoos.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -1563,8 +1822,20 @@ $util.toJson($ListRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -1588,12 +1859,147 @@ $util.toJson($ListRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listFoos.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listFoos.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Subscription.onCreateBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateBar.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateBar.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateFoo.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateFoo.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onCreateFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreateFooBar.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreateFooBar.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteBar.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteBar.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteFoo.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteFoo.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeleteFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeleteFooBar.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeleteFooBar.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateBar.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateBar.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateFoo.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateFoo.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateFoo.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdateFooBar.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdateFooBar.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdateFooBar.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", } `; diff --git a/packages/amplify-graphql-relational-transformer/src/resolvers.ts b/packages/amplify-graphql-relational-transformer/src/resolvers.ts index 97da8250ec7..1104c0bbc61 100644 --- a/packages/amplify-graphql-relational-transformer/src/resolvers.ts +++ b/packages/amplify-graphql-relational-transformer/src/resolvers.ts @@ -6,6 +6,7 @@ import { Table } from '@aws-cdk/aws-dynamodb'; import * as cdk from '@aws-cdk/core'; import { ObjectTypeDefinitionNode } from 'graphql'; import { + and, bool, compoundExpression, DynamoDBMappingTemplate, @@ -13,16 +14,22 @@ import { Expression, ifElse, iff, + int, + isNullOrEmpty, list, + methodCall, + not, nul, obj, ObjectNode, or, print, + qref, raw, ref, set, str, + toJson, } from 'graphql-mapping-template'; import { applyCompositeKeyConditionExpression, @@ -36,6 +43,8 @@ import { import { HasManyDirectiveConfiguration, HasOneDirectiveConfiguration } from './types'; import { getConnectionAttributeName } from './utils'; +const authFilter = ref('ctx.stash.authFilter'); + export function makeGetItemConnectionWithKeyResolver(config: HasOneDirectiveConfiguration, ctx: TransformerContextProvider) { const { connectionFields, field, fields, object, relatedType, relatedTypeIndex } = config; assert(relatedTypeIndex.length > 0); @@ -44,8 +53,11 @@ export function makeGetItemConnectionWithKeyResolver(config: HasOneDirectiveConf const { keySchema } = table as any; const dataSource = ctx.api.host.getDataSource(`${relatedType.name.value}Table`); const partitionKeyName = keySchema[0].attributeName; - const keyObj = { - [partitionKeyName]: ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${localFields[0]}, "${NONE_VALUE}"))`), + let totalExpressions = [`${partitionKeyName} = :${partitionKeyName}`]; + let totalExpressionValues: Record = { + [`:${partitionKeyName}`]: ref( + `util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${localFields[0]}, "${NONE_VALUE}")))`, + ), }; // Add a composite sort key or simple sort key if there is one. @@ -54,11 +66,16 @@ export function makeGetItemConnectionWithKeyResolver(config: HasOneDirectiveConf const sortKeyName = keySchema[1].attributeName; const condensedSortKeyValue = condenseRangeKey(rangeKeyFields.map(keyField => `\${ctx.source.${keyField}}`)); - keyObj[sortKeyName] = ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank("${condensedSortKeyValue}", "${NONE_VALUE}"))`); + totalExpressions.push(`${sortKeyName} = :${sortKeyName}`); + totalExpressionValues[`:${sortKeyName}`] = ref( + `util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank("${condensedSortKeyValue}", "${NONE_VALUE}")))`, + ); } else if (relatedTypeIndex.length === 2) { const sortKeyName = keySchema[1].attributeName; - - keyObj[sortKeyName] = ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${localFields[1]}, "${NONE_VALUE}"))`); + totalExpressions.push(`${sortKeyName} = :${sortKeyName}`); + totalExpressionValues[`:${sortKeyName}`] = ref( + `util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.source.${localFields[1]}, "${NONE_VALUE}")))`, + ); } const resolver = ctx.resolvers.generateQueryResolver( @@ -71,16 +88,49 @@ export function makeGetItemConnectionWithKeyResolver(config: HasOneDirectiveConf or(localFields.map(f => raw(`$util.isNull($ctx.source.${f})`))), raw('#return'), compoundExpression([ - DynamoDBMappingTemplate.getItem({ - key: obj(keyObj), - }), + set(ref('GetRequest'), obj({ version: str('2018-05-29'), operation: str('Query') })), + qref( + methodCall( + ref('GetRequest.put'), + str('query'), + obj({ + expression: str(totalExpressions.join(' AND ')), + expressionValues: obj(totalExpressionValues), + }), + ), + ), + iff( + not(isNullOrEmpty(authFilter)), + qref( + methodCall( + ref('GetRequest.put'), + str('filter'), + methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), authFilter)), + ), + ), + ), + toJson(ref('GetRequest')), ]), ), ), `${object.name.value}.${field.name.value}.req.vtl`, ), MappingTemplate.s3MappingTemplateFromString( - print(DynamoDBMappingTemplate.dynamoDBResponse(false)), + print( + DynamoDBMappingTemplate.dynamoDBResponse( + false, + compoundExpression([ + ifElse( + and([not(ref('ctx.result.items.isEmpty()')), equals(ref('ctx.result.scannedCount'), int(1))]), + toJson(ref('ctx.result.items[0]')), + compoundExpression([ + iff(and([ref('ctx.result.items.isEmpty()'), equals(ref('ctx.result.scannedCount'), int(1))]), ref('util.unauthorized()')), + toJson(nul()), + ]), + ), + ]), + ), + ), `${object.name.value}.${field.name.value}.res.vtl`, ), ); @@ -115,6 +165,36 @@ export function makeQueryConnectionWithKeyResolver(config: HasManyDirectiveConfi setup.push(applyCompositeKeyConditionExpression(sortKeyFieldNames, 'query', toCamelCase(sortKeyFieldNames), sortKeyFieldName)); } } + // add setup filter to query + setup.push( + ifElse( + not(isNullOrEmpty(authFilter)), + compoundExpression([ + set(ref('filter'), authFilter), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), obj({ and: list([ref('filter'), ref('ctx.args.filter')]) }))), + ]), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), ref('ctx.args.filter'))), + ), + iff( + not(isNullOrEmpty(ref('filter'))), + compoundExpression([ + set( + ref(`filterExpression`), + methodCall(ref('util.parseJson'), methodCall(ref('util.transform.toDynamoDBFilterExpression'), ref('filter'))), + ), + iff( + not(methodCall(ref('util.isNullOrBlank'), ref('filterExpression.expression'))), + compoundExpression([ + iff( + equals(methodCall(ref('filterEpression.expressionValues.size')), int(0)), + qref(methodCall(ref('filterEpression.remove'), str('expressionValues'))), + ), + set(ref('filter'), ref('filterExpression')), + ]), + ), + ]), + ), + ); const queryArguments = { query: raw('$util.toJson($query)'), @@ -123,7 +203,7 @@ export function makeQueryConnectionWithKeyResolver(config: HasManyDirectiveConfi ifElse(equals(ref('context.args.sortDirection'), str('ASC')), bool(true), bool(false)), bool(true), ), - filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()), + filter: ifElse(ref('filter'), ref('util.toJson($filter)'), nul()), limit: ref('limit'), nextToken: ifElse(ref('context.args.nextToken'), ref('util.toJson($context.args.nextToken)'), nul()), } as any; diff --git a/packages/amplify-graphql-relational-transformer/src/schema.ts b/packages/amplify-graphql-relational-transformer/src/schema.ts index db278a06b0a..905af1548cd 100644 --- a/packages/amplify-graphql-relational-transformer/src/schema.ts +++ b/packages/amplify-graphql-relational-transformer/src/schema.ts @@ -65,7 +65,7 @@ function generateModelXConnectionType( let connectionTypeExtension = blankObjectExtension(tableXConnectionName); connectionTypeExtension = extensionWithFields(connectionTypeExtension, [ - makeField('items', [], makeListType(makeNamedType(tableXConnectionName))), + makeField('items', [], makeListType(makeNamedType(relatedType.name.value))), ]); connectionTypeExtension = extensionWithFields(connectionTypeExtension, [makeField('nextToken', [], makeNamedType('String'))]); diff --git a/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap b/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap index 4f2f780d9da..49eab512b4c 100644 --- a/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap +++ b/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap @@ -604,6 +604,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.createPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.createPost.req.vtl": "## [Start] Create Request template. ** ## Begin - key condition ** #if( $ctx.stash.metadata.modelObjectKey ) @@ -688,13 +694,20 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) #end $util.toJson($PutObject) ## [End] Create Request template. **", - "Mutation.createPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.createPost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Mutation.deletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.deletePost.req.vtl": "## [Start] Delete Request template. ** #set( $DeleteRequest = { \\"version\\": \\"2018-05-29\\", @@ -752,13 +765,14 @@ $util.qr($DeleteRequest.put(\\"key\\", $Key)) #end $util.toJson($DeleteRequest) ## [End] Delete Request template. **", - "Mutation.deletePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.deletePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Mutation.updatePost.init.1.req.vtl": "## [Start] Initialization default values. ** $util.qr($ctx.stash.put(\\"defaultValues\\", $util.defaultIfNull($ctx.stash.defaultValues, {}))) #set( $updatedAt = $util.time.nowISO8601() ) @@ -768,6 +782,12 @@ $util.toJson({ \\"payload\\": {} }) ## [End] Initialization default values. **", + "Mutation.updatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Mutation.updatePost.req.vtl": "## [Start] Mutation Update resolver. ** ## Set the default values to put request ** #set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) @@ -897,35 +917,70 @@ $util.qr($update.put(\\"expression\\", \\"$expression\\")) #end $util.toJson($UpdateItem) ## [End] Mutation Update resolver. **", - "Mutation.updatePost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Mutation.updatePost.res.vtl": "## [Start] ResponseTemplate. ** +$util.qr($ctx.result.put(\\"__operation\\", \\"Mutation\\")) #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", + "Query.getPost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.getPost.req.vtl": "## [Start] Get Request template. ** #set( $GetRequest = { \\"version\\": \\"2018-05-29\\", - \\"operation\\": \\"GetItem\\" + \\"operation\\": \\"Query\\" } ) #if( $ctx.stash.metadata.modelObjectKey ) - #set( $key = $ctx.stash.metadata.modelObjectKey ) + #set( $expression = \\"\\" ) + #set( $expressionValues = {} ) + #foreach( $item in $ctx.stash.metadata.modelObjectKey.entrySet() ) + #set( $expression = \\"$expression$item.key = :$item.key AND \\" ) + $util.qr($expressionValues.put(\\":$item.key\\", $item.value)) + #end + #set( $expression = $expression.replaceAll(\\"AND $\\", \\"\\") ) + #set( $query = { + \\"expression\\": $expression, + \\"expressionValues\\": $expressionValues +} ) #else - #set( $key = { - \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.id) + #set( $query = { + \\"expression\\": \\"id = :id\\", + \\"expressionValues\\": { + \\":id\\": $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.id)) + } } ) #end -$util.qr($GetRequest.put(\\"key\\", $key)) +$util.qr($GetRequest.put(\\"query\\", $query)) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + $util.qr($GetRequest.put(\\"filter\\", $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.stash.authFilter)))) +#end $util.toJson($GetRequest) ## [End] Get Request template. **", - "Query.getPost.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.getPost.res.vtl": "## [Start] Get Response template. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) +#end +#if( !$ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) + $util.toJson($ctx.result.items[0]) #else - $util.toJson($ctx.result) + #if( $ctx.result.items.isEmpty() && $ctx.result.scannedCount == 1 ) +$util.unauthorized() + #end + $util.toJson(null) #end -## [End] Get ResponseTemplate. **", +## [End] Get Response template. **", + "Query.listPosts.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", "Query.listPosts.req.vtl": "## [Start] List Request. ** #set( $limit = $util.defaultIfNull($context.args.limit, 100) ) #set( $ListRequest = { @@ -935,8 +990,20 @@ $util.toJson($GetRequest) #if( $context.args.nextToken ) #set( $ListRequest.nextToken = $context.args.nextToken ) #end -#if( $context.args.filter ) - #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($ctx.args.filter)) ) +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = { + \\"and\\": [$filter, $ctx.args.filter] +} ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( !$util.isNullOrEmpty($filter) ) + #set( $filterExpression = $util.parseJson($util.transform.toDynamoDBFilterExpression($filter)) ) #if( !$util.isNullOrBlank($filterExpression.expression) ) #if( $filterEpression.expressionValues.size() == 0 ) $util.qr($filterEpression.remove(\\"expressionValues\\")) @@ -960,13 +1027,13 @@ $util.toJson($GetRequest) #end $util.toJson($ListRequest) ## [End] List Request. **", - "Query.listPosts.res.vtl": "## [Start] Get ResponseTemplate. ** + "Query.listPosts.res.vtl": "## [Start] ResponseTemplate. ** #if( $ctx.error ) $util.error($ctx.error.message, $ctx.error.type) #else $util.toJson($ctx.result) #end -## [End] Get ResponseTemplate. **", +## [End] ResponseTemplate. **", "Query.searchPosts.req.vtl": "#set( $indexPath = \\"/post/doc/_search\\" ) #set( $nonKeywordFields = [] ) #set( $sortValues = [] ) @@ -1006,6 +1073,25 @@ $util.toJson($ListRequest) $util.qr($aggregateValues.put(\\"$aggItem.name\\", {\\"$aggItem.type\\": {\\"field\\": \\"\${aggItem.field}.keyword\\"}})) #end #end +#if( !$util.isNullOrEmpty($ctx.stash.authFilter) ) + #set( $filter = $ctx.stash.authFilter ) + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = [{ + \\"bool\\": { + \\"must\\": [$ctx.stash.authFilter, $util.transform.toElasticsearchQueryDSL($ctx.args.filter)] + } +}] ) + #end +#else + #if( !$util.isNullOrEmpty($ctx.args.filter) ) + #set( $filter = $ctx.args.filter ) + #end +#end +#if( $util.isNullOrEmpty($filter) ) + #set( $filter = { + \\"match_all\\": {} +} ) +#end { \\"version\\": \\"2018-05-29\\", \\"operation\\": \\"GET\\", @@ -1017,13 +1103,7 @@ $util.toJson($ListRequest) \\"size\\": #if( $context.args.limit ) $context.args.limit #else 100 #end, \\"sort\\": $sortValues, \\"version\\": false, - \\"query\\": #if( $context.args.filter ) -$util.transform.toElasticsearchQueryDSL($ctx.args.filter) -#else -{ - \\"match_all\\": {} - } -#end, + \\"query\\": $util.toJson($filter), \\"aggs\\": $util.toJson($aggregateValues) } } @@ -1059,6 +1139,51 @@ $util.toJson({ \\"nextToken\\": $nextToken, \\"aggregateItems\\": $aggregateValues })", + "Subscription.onCreatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onCreatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onCreatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onDeletePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onDeletePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onDeletePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", + "Subscription.onUpdatePost.postAuth.1.req.vtl": "## [Start] Sandbox Mode Disabled. ** +#if( !$ctx.stash.get(\\"hasAuth\\") ) + $util.unauthorized() +#end +$util.toJson({}) +## [End] Sandbox Mode Disabled. **", + "Subscription.onUpdatePost.req.vtl": "## [Start] Subscription Request template. ** +$util.toJson({ + \\"version\\": \\"2018-05-29\\", + \\"payload\\": {} +}) +## [End] Subscription Request template. **", + "Subscription.onUpdatePost.res.vtl": "## [Start] Subscription Response template. ** +$util.toJson(null) +## [End] Subscription Response template. **", } `; diff --git a/packages/amplify-graphql-searchable-transformer/src/generate-resolver-vtl.ts b/packages/amplify-graphql-searchable-transformer/src/generate-resolver-vtl.ts index ccef9dc1ca9..9c93786731f 100644 --- a/packages/amplify-graphql-searchable-transformer/src/generate-resolver-vtl.ts +++ b/packages/amplify-graphql-searchable-transformer/src/generate-resolver-vtl.ts @@ -17,9 +17,13 @@ import { Expression, bool, methodCall, + isNullOrEmpty, + not, } from 'graphql-mapping-template'; import { ResourceConstants } from 'graphql-transformer-common'; +const authFilter = ref('ctx.stash.authFilter'); + export function requestTemplate(primaryKey: string, nonKeywordFields: Expression[], includeVersion: boolean = false, type: string): string { return print( compoundExpression([ @@ -64,19 +68,32 @@ export function requestTemplate(primaryKey: string, nonKeywordFields: Expression qref('$aggregateValues.put("$aggItem.name", {"$aggItem.type": {"field": "${aggItem.field}.keyword"}})'), ), ]), + ifElse( + not(isNullOrEmpty(authFilter)), + compoundExpression([ + set(ref('filter'), authFilter), + iff( + not(isNullOrEmpty(ref('ctx.args.filter'))), + set( + ref('filter'), + list([ + obj({ + bool: obj({ must: list([ref('ctx.stash.authFilter'), ref('util.transform.toElasticsearchQueryDSL($ctx.args.filter)')]) }), + }), + ]), + ), + ), + ]), + iff(not(isNullOrEmpty(ref('ctx.args.filter'))), set(ref('filter'), ref('ctx.args.filter'))), + ), + iff(isNullOrEmpty(ref('filter')), set(ref('filter'), obj({ match_all: obj({}) }))), SearchableMappingTemplate.searchTemplate({ path: str('$indexPath'), size: ifElse(ref('context.args.limit'), ref('context.args.limit'), int(ResourceConstants.DEFAULT_SEARCHABLE_PAGE_LIMIT), true), search_after: ref('util.base64Decode($context.args.nextToken)'), from: ref('context.args.from'), version: bool(includeVersion), - query: ifElse( - ref('context.args.filter'), - ref('util.transform.toElasticsearchQueryDSL($ctx.args.filter)'), - obj({ - match_all: obj({}), - }), - ), + query: methodCall(ref('util.toJson'), ref('filter')), sort: ref('sortValues'), aggs: ref('util.toJson($aggregateValues)'), }), diff --git a/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts b/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts index a94a93ee74e..d1832a755d3 100644 --- a/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts +++ b/packages/amplify-graphql-searchable-transformer/src/graphql-searchable-transformer.ts @@ -138,7 +138,7 @@ export class SearchableModelTransformer extends TransformerPluginBase { MappingTemplate.s3MappingTemplateFromString(responseTemplate(false), `${typeName}.${def.fieldName}.res.vtl`), ); resolver.mapToStack(stack); - context.resolvers.addResolver(type, def.fieldName, resolver); + context.resolvers.addResolver(typeName, def.fieldName, resolver); } createStackOutputs(stack, domain.domainEndpoint, context.api.apiId, domain.domainArn); diff --git a/packages/amplify-graphql-transformer-core/src/config/index.ts b/packages/amplify-graphql-transformer-core/src/config/index.ts index 7cfa3497922..58b0911cbdb 100644 --- a/packages/amplify-graphql-transformer-core/src/config/index.ts +++ b/packages/amplify-graphql-transformer-core/src/config/index.ts @@ -1,21 +1,2 @@ export { TransformerProjectConfig } from './project-config'; -export { - TransformConfig, - ConflictDetectionType, - ConflictHandlerType, - ResolverConfig, - SyncConfig, - SyncConfigLambda, - SyncConfigOptimistic, - SyncConfigServer, - LambdaConflictHandler, - AppSyncAuthConfiguration, - AppSyncAuthConfigurationAPIKeyEntry, - AppSyncAuthConfigurationEntry, - AppSyncAuthConfigurationIAMEntry, - ApiKeyConfig, - AppSyncAuthConfigurationOIDCEntry, - AppSyncAuthConfigurationUserPoolEntry, - AppSyncAuthMode, - UserPoolConfig, -} from './transformer-config'; +export * from './transformer-config'; diff --git a/packages/amplify-graphql-transformer-core/src/config/transformer-config.ts b/packages/amplify-graphql-transformer-core/src/config/transformer-config.ts index c98cfad4f3d..1b044d1a36e 100644 --- a/packages/amplify-graphql-transformer-core/src/config/transformer-config.ts +++ b/packages/amplify-graphql-transformer-core/src/config/transformer-config.ts @@ -4,56 +4,13 @@ export interface TransformMigrationConfig { }; } -// Auth Config -export type AppSyncAuthMode = 'API_KEY' | 'AMAZON_COGNITO_USER_POOLS' | 'AWS_IAM' | 'OPENID_CONNECT'; -export type AppSyncAuthConfiguration = { - defaultAuthentication: AppSyncAuthConfigurationEntry; - additionalAuthenticationProviders: Array; -}; - -export type AppSyncAuthConfigurationEntry = - | AppSyncAuthConfigurationUserPoolEntry - | AppSyncAuthConfigurationAPIKeyEntry - | AppSyncAuthConfigurationIAMEntry - | AppSyncAuthConfigurationOIDCEntry; -export type AppSyncAuthConfigurationAPIKeyEntry = { - authenticationType: 'API_KEY'; - apiKeyConfig: ApiKeyConfig; -}; -export type AppSyncAuthConfigurationUserPoolEntry = { - authenticationType: 'AMAZON_COGNITO_USER_POOLS'; - userPoolConfig: UserPoolConfig; -}; -export type AppSyncAuthConfigurationIAMEntry = { - authenticationType: 'AWS_IAM'; -}; - -export type AppSyncAuthConfigurationOIDCEntry = { - authenticationType: 'OPENID_CONNECT'; - openIDConnectConfig: OpenIDConnectConfig; -}; - -export type ApiKeyConfig = { - description?: string; - apiKeyExpirationDays: number; -}; -export type UserPoolConfig = { - userPoolId: string; -}; -export type OpenIDConnectConfig = { - name: string; - issuerUrl: string; - clientId?: string; - iatTTL?: number; - authTTL?: number; -}; - // Sync Config export const enum ConflictHandlerType { OPTIMISTIC = 'OPTIMISTIC_CONCURRENCY', AUTOMERGE = 'AUTOMERGE', LAMBDA = 'LAMBDA', } + export type ConflictDetectionType = 'VERSION' | 'NONE'; export type SyncConfigOptimistic = { ConflictDetection: ConflictDetectionType; @@ -79,10 +36,6 @@ export type ResolverConfig = { project?: SyncConfig; models?: Record; }; -/** - * The transform config is specified in transform.conf.json within an Amplify - * API project directory. - */ export interface TransformConfig { /** * The transform library uses a "StackMapping" to determine which stack @@ -95,7 +48,9 @@ export interface TransformConfig { * overrides to get specific behavior out of the transformer. Users may * override the default stack mapping to customize behavior. */ - StackMapping?: Record; + StackMapping?: { + [resourceId: string]: string; + }; /** * Provide build time options to GraphQL Transformer constructor functions. @@ -103,9 +58,10 @@ export interface TransformConfig { * need to be set at build time. E.G. DeletionPolicies cannot depend on parameters. */ TransformerOptions?: { - [transformer: string]: Record; + [transformer: string]: { + [option: string]: any; + }; }; - /** * Object which states info about a resolver's configuration * Such as sync configuration for appsync local support diff --git a/packages/amplify-graphql-transformer-core/src/graphql-api.ts b/packages/amplify-graphql-transformer-core/src/graphql-api.ts index 71d9fa52dc8..fba65cd31e8 100644 --- a/packages/amplify-graphql-transformer-core/src/graphql-api.ts +++ b/packages/amplify-graphql-transformer-core/src/graphql-api.ts @@ -113,6 +113,7 @@ export class IamResource implements APIIAMResourceProvider { export type TransformerAPIProps = GraphqlApiProps & { readonly createApiKey?: boolean; readonly host?: TransformHostProvider; + readonly globalSandboxModeEnv?: string; }; export class GraphQLApi extends GraphqlApiBase implements GraphQLAPIProvider { /** @@ -125,7 +126,7 @@ export class GraphQLApi extends GraphqlApiBase implements GraphQLAPIProvider { * The TransformHost object provides resource creation utilities in AWS * such as a LambdaDataSource or a DynamoDBDataSource */ - public readonly host: TransformHostProvider + public readonly host: TransformHostProvider; /** * the ARN of the API @@ -161,6 +162,11 @@ export class GraphQLApi extends GraphqlApiBase implements GraphQLAPIProvider { */ public readonly apiKey?: string; + /** + * Global Sandbox Mode for GraphQL API + */ + public readonly globalSandboxModeEnabled?: boolean; + private schemaResource: CfnGraphQLSchema; private api: CfnGraphQLApi; private apiKeyResource?: CfnApiKey; @@ -198,7 +204,9 @@ export class GraphQLApi extends GraphqlApiBase implements GraphQLAPIProvider { this.schema = props.schema ?? new TransformerSchema(); this.schemaResource = this.schema.bind(this); - if (props.createApiKey && modes.some(mode => mode.authorizationType === AuthorizationType.API_KEY)) { + const hasApiKey = modes.some(mode => mode.authorizationType === AuthorizationType.API_KEY); + + if (props.createApiKey && hasApiKey) { const config = modes.find((mode: AuthorizationMode) => { return mode.authorizationType === AuthorizationType.API_KEY && mode.apiKeyConfig; })?.apiKeyConfig; @@ -207,13 +215,14 @@ export class GraphQLApi extends GraphqlApiBase implements GraphQLAPIProvider { this.apiKey = this.apiKeyResource.attrApiKey; } + if (hasApiKey && !!props.globalSandboxModeEnv) this.globalSandboxModeEnabled = true; + if (props.host) { this.host = props.host; this.host.setAPI(this); - } - else { + } else { this.host = new DefaultTransformHost({ - api: this + api: this, }); } } diff --git a/packages/amplify-graphql-transformer-core/src/index.ts b/packages/amplify-graphql-transformer-core/src/index.ts index 6ddfd7b974a..6c6627b257c 100644 --- a/packages/amplify-graphql-transformer-core/src/index.ts +++ b/packages/amplify-graphql-transformer-core/src/index.ts @@ -8,25 +8,29 @@ export { ConflictHandlerType, ResolverConfig, SyncConfig, - SyncConfigLambda, SyncConfigOptimistic, SyncConfigServer, + SyncConfigLambda, TransformConfig, TransformerProjectConfig, - AppSyncAuthConfiguration, - AppSyncAuthConfigurationAPIKeyEntry, - AppSyncAuthConfigurationEntry, - AppSyncAuthConfigurationIAMEntry, - ApiKeyConfig, - AppSyncAuthConfigurationOIDCEntry, - AppSyncAuthConfigurationUserPoolEntry, - AppSyncAuthMode, - UserPoolConfig, - LambdaConflictHandler, } from './config/index'; -export { collectDirectives, collectDirectivesByTypeNames, DirectiveWrapper } from './utils'; +export { + collectDirectives, + collectDirectivesByTypeNames, + DirectiveWrapper, + getSandboxModeEnvNameFromDirectiveSet, + getSandboxModeEnvNameFromNodeMap, + IAM_AUTH_ROLE_PARAMETER, + IAM_UNAUTH_ROLE_PARAMETER, +} from './utils'; export * from './errors'; -export { TransformerModelBase, TransformerModelEnhancerBase, TransformerPluginBase } from './transformation/transformer-plugin-base'; +export { + TransformerModelBase, + TransformerModelEnhancerBase, + TransformerPluginBase, + TransformerAuthBase, +} from './transformation/transformer-plugin-base'; +export { TransformerResolver } from './transformer-context'; /** * Returns the extra set of directives that are supported by AppSync service */ diff --git a/packages/amplify-graphql-transformer-core/src/transform-host.ts b/packages/amplify-graphql-transformer-core/src/transform-host.ts index a72f94cf87d..5ede7441a0a 100644 --- a/packages/amplify-graphql-transformer-core/src/transform-host.ts +++ b/packages/amplify-graphql-transformer-core/src/transform-host.ts @@ -26,6 +26,7 @@ export interface DefaultTransformHostOptions { export class DefaultTransformHost implements TransformHostProvider { private dataSources: Map = new Map(); + private resolvers: Map = new Map(); private api: GraphQLApi; public constructor(options: DefaultTransformHostOptions) { @@ -45,6 +46,16 @@ export class DefaultTransformHost implements TransformHostProvider { } }; + public hasResolver = (typeName: string, fieldName: string) => { + return this.resolvers.has(`${typeName}:${fieldName}`); + }; + + public getResolver = (typeName: string, fieldName: string): CfnResolver | void => { + if (this.resolvers.has(`${typeName}:${fieldName}`)) { + return this.resolvers.get(`${typeName}:${fieldName}`); + } + }; + addSearchableDataSource( name: string, awsRegion: string, @@ -125,7 +136,7 @@ export class DefaultTransformHost implements TransformHostProvider { dataSourceName?: string, pipelineConfig?: string[], stack?: Stack, - ) { + ): CfnResolver { if (dataSourceName && !Token.isUnresolved(dataSourceName) && !this.dataSources.has(dataSourceName)) { throw new Error(`DataSource ${dataSourceName} is missing in the API`); } @@ -168,6 +179,7 @@ export class DefaultTransformHost implements TransformHostProvider { }, }); this.api.addSchemaDependency(resolver); + this.resolvers.set(`${typeName}:${fieldName}`, resolver); return resolver; } else { throw new Error('Resolver needs either dataSourceName or pipelineConfig to be passed'); diff --git a/packages/amplify-graphql-transformer-core/src/transformation/sync-utils.ts b/packages/amplify-graphql-transformer-core/src/transformation/sync-utils.ts index 7d207ffa4e2..5818000f4c0 100644 --- a/packages/amplify-graphql-transformer-core/src/transformation/sync-utils.ts +++ b/packages/amplify-graphql-transformer-core/src/transformation/sync-utils.ts @@ -90,7 +90,7 @@ export function syncDataSourceConfig(): DeltaSyncConfig { export function validateResolverConfigForType(ctx: TransformerSchemaVisitStepContextProvider, typeName: string): void { const resolverConfig = ctx.getResolverConfig(); const typeResolverConfig = resolverConfig?.models?.[typeName]; - if (!typeResolverConfig || !typeResolverConfig.ConflictDetection || !typeResolverConfig.ConflictHandler) { + if (typeResolverConfig && !typeResolverConfig.ConflictDetection && !typeResolverConfig.ConflictHandler) { console.warn(`Invalid resolverConfig for type ${typeName}. Using the project resolverConfig instead.`); } } diff --git a/packages/amplify-graphql-transformer-core/src/transformation/transform.ts b/packages/amplify-graphql-transformer-core/src/transformation/transform.ts index 2571efec502..33ad0ffa85a 100644 --- a/packages/amplify-graphql-transformer-core/src/transformation/transform.ts +++ b/packages/amplify-graphql-transformer-core/src/transformation/transform.ts @@ -4,6 +4,7 @@ import { GraphQLAPIProvider, TransformerPluginProvider, TransformHostProvider, + AppSyncAuthConfiguration, } from '@aws-amplify/graphql-transformer-interfaces'; import { AuthorizationMode, AuthorizationType } from '@aws-cdk/aws-appsync'; import { App, Aws, CfnOutput, Fn } from '@aws-cdk/core'; @@ -23,13 +24,13 @@ import { TypeExtensionNode, UnionTypeDefinitionNode, } from 'graphql'; -import { AppSyncAuthConfiguration, TransformConfig } from '../config/transformer-config'; import { InvalidTransformerError, SchemaValidationError, UnknownDirectiveError } from '../errors'; import { GraphQLApi } from '../graphql-api'; import { TransformerContext } from '../transformer-context'; import { TransformerOutput } from '../transformer-context/output'; import { StackManager } from '../transformer-context/stack-manager'; -import { adoptAuthModes } from '../utils/authType'; +import { adoptAuthModes, IAM_AUTH_ROLE_PARAMETER, IAM_UNAUTH_ROLE_PARAMETER } from '../utils/authType'; +import { TransformConfig } from '../config'; import * as SyncUtils from './sync-utils'; import Template, { DeploymentResources } from './types'; @@ -42,7 +43,8 @@ import { matchInputFieldDirective, sortTransformerPlugins, } from './utils'; -import { validateModelSchema } from './validation'; +import { validateModelSchema, validateAuthModes } from './validation'; +import { getSandboxModeEnvNameFromNodeMap } from '../utils/sandbox-mode'; // eslint-disable-next-line @typescript-eslint/ban-types function isFunction(obj: any): obj is Function { @@ -103,6 +105,8 @@ export class GraphQLTransform { additionalAuthenticationProviders: [], }; + validateAuthModes(this.authConfig); + this.buildParameters = options.buildParameters || {}; this.stackMappingOverrides = options.stackMapping || {}; this.transformConfig = options.transformConfig || {}; @@ -124,6 +128,7 @@ export class GraphQLTransform { this.app, parsedDocument, this.stackMappingOverrides, + this.authConfig, this.options.featureFlags, this.transformConfig.ResolverConfig, ); @@ -136,6 +141,7 @@ export class GraphQLTransform { aws_iam: true, aws_oidc: true, aws_cognito_user_pools: true, + allow_public_data_access_with_api_key: true, deprecated: true, }, ); @@ -143,6 +149,9 @@ export class GraphQLTransform { for (const transformer of this.transformers) { allModelDefinitions = allModelDefinitions.concat(...transformer.typeDefinitions, transformer.directive); } + const ampGlobalIdx = allModelDefinitions.findIndex(el => el.kind === 'ObjectTypeDefinition' && el.name.value === 'AMPLIFY_GLOBAL'); + if (ampGlobalIdx > -1) allModelDefinitions.splice(ampGlobalIdx, 1); + const errors = validateModelSchema({ kind: Kind.DOCUMENT, definitions: allModelDefinitions, @@ -214,7 +223,6 @@ export class GraphQLTransform { // Synth the API and make it available to allow transformer plugins to manipulate the API const stackManager = context.stackManager as StackManager; const output: TransformerOutput = context.output as TransformerOutput; - const api = this.generateGraphQlApi(stackManager, output); // generate resolvers @@ -253,11 +261,13 @@ export class GraphQLTransform { type: 'String', }).valueAsString; const envName = stackManager.getParameter('env'); + const globalSandboxModeEnv = getSandboxModeEnvNameFromNodeMap(output.nodeMap); assert(envName); const api = new GraphQLApi(rootStack, 'GraphQLAPI', { name: `${apiName}-${envName.valueAsString}`, authorizationConfig, host: this.options.host, + globalSandboxModeEnv, }); const authModes = [authorizationConfig.defaultAuthorization, ...(authorizationConfig.additionalAuthorizationModes || [])].map( mode => mode?.authorizationType, @@ -286,6 +296,11 @@ export class GraphQLTransform { }); } + if (authModes.includes(AuthorizationType.IAM)) { + stackManager.addParameter(IAM_AUTH_ROLE_PARAMETER, { type: 'String' }); + stackManager.addParameter(IAM_UNAUTH_ROLE_PARAMETER, { type: 'String' }); + } + new CfnOutput(rootStack, 'GraphQLAPIIdOutput', { value: api.apiId, description: 'Your GraphQL API ID.', diff --git a/packages/amplify-graphql-transformer-core/src/transformation/transformer-plugin-base.ts b/packages/amplify-graphql-transformer-core/src/transformation/transformer-plugin-base.ts index f0f9c86d910..9dad23a4873 100644 --- a/packages/amplify-graphql-transformer-core/src/transformation/transformer-plugin-base.ts +++ b/packages/amplify-graphql-transformer-core/src/transformation/transformer-plugin-base.ts @@ -10,6 +10,7 @@ import { DataSourceInstance, TransformerPluginProvider, TransformerModelEnhancementProvider, + TransformerAuthProvider, } from '@aws-amplify/graphql-transformer-interfaces'; import { @@ -176,3 +177,9 @@ export abstract class TransformerModelEnhancerBase extends TransformerModelBase super(name, doc, type); } } + +export abstract class TransformerAuthBase extends TransformerPluginBase implements TransformerAuthProvider { + constructor(name: string, doc: DocumentNode | string, type: TransformerPluginType = TransformerPluginType.AUTH) { + super(name, doc, type); + } +} diff --git a/packages/amplify-graphql-transformer-core/src/transformation/utils.ts b/packages/amplify-graphql-transformer-core/src/transformation/utils.ts index e7cb2863963..24523f2256c 100644 --- a/packages/amplify-graphql-transformer-core/src/transformation/utils.ts +++ b/packages/amplify-graphql-transformer-core/src/transformation/utils.ts @@ -171,6 +171,7 @@ export function sortTransformerPlugins(plugins: TransformerPluginProvider[]): Tr TransformerPluginType.DATA_SOURCE_PROVIDER, TransformerPluginType.DATA_SOURCE_ENHANCER, TransformerPluginType.GENERIC, + TransformerPluginType.AUTH, ]; return plugins.sort((a, b) => { const aIdx = SORT_ORDER.indexOf(a.pluginType); diff --git a/packages/amplify-graphql-transformer-core/src/transformation/validation.ts b/packages/amplify-graphql-transformer-core/src/transformation/validation.ts index 4e94fd7b6e4..a74afcd62bc 100644 --- a/packages/amplify-graphql-transformer-core/src/transformation/validation.ts +++ b/packages/amplify-graphql-transformer-core/src/transformation/validation.ts @@ -54,6 +54,9 @@ import { NoUndefinedVariables } from 'graphql/validation/rules/NoUndefinedVariab import { NoUnusedVariables } from 'graphql/validation/rules/NoUnusedVariables'; import { UniqueDirectivesPerLocation } from 'graphql/validation/rules/UniqueDirectivesPerLocation'; +// AuthMode Types +import { AppSyncAuthConfiguration, AppSyncAuthMode } from '@aws-amplify/graphql-transformer-interfaces'; + /** * This set includes all validation rules defined by the GraphQL spec. * @@ -109,6 +112,7 @@ directive @aws_api_key on FIELD_DEFINITION | OBJECT directive @aws_iam on FIELD_DEFINITION | OBJECT directive @aws_oidc on FIELD_DEFINITION | OBJECT directive @aws_cognito_user_pools(cognito_groups: [String!]) on FIELD_DEFINITION | OBJECT +directive @allow_public_data_access_with_api_key(in: [String!]) on OBJECT # Allows transformer libraries to deprecate directive arguments. directive @deprecated(reason: String) on FIELD_DEFINITION | INPUT_FIELD_DEFINITION | ENUM | ENUM_VALUE @@ -142,3 +146,21 @@ export const validateModelSchema = (doc: DocumentNode) => { const schema = buildASTSchema(fullDocument); return validate(schema, fullDocument, specifiedRules); }; + +export const validateAuthModes = (authConfig: AppSyncAuthConfiguration) => { + let additionalAuthModes: AppSyncAuthMode[] = []; + + if (authConfig.additionalAuthenticationProviders) { + additionalAuthModes = authConfig.additionalAuthenticationProviders.map(p => p.authenticationType).filter(t => !!t); + } + + const authModes: AppSyncAuthMode[] = [...additionalAuthModes, authConfig.defaultAuthentication.authenticationType]; + + for (let i = 0; i < authModes.length; i++) { + const mode = authModes[i]; + + if (mode !== 'API_KEY' && mode !== 'AMAZON_COGNITO_USER_POOLS' && mode !== 'AWS_IAM' && mode !== 'OPENID_CONNECT') { + throw new Error(`Invalid auth mode ${mode}`); + } + } +}; diff --git a/packages/amplify-graphql-transformer-core/src/transformer-context/datasource.ts b/packages/amplify-graphql-transformer-core/src/transformer-context/datasource.ts index ded8e6cd888..544438499a3 100644 --- a/packages/amplify-graphql-transformer-core/src/transformer-context/datasource.ts +++ b/packages/amplify-graphql-transformer-core/src/transformer-context/datasource.ts @@ -23,4 +23,8 @@ export class TransformerDataSourceManager implements TransformerDataSourceManage collectDataSources = (): Readonly> => { return this.dataSourceMap; }; + + has = (name: string): boolean => { + return this.dataSourceMap.has(name); + }; } diff --git a/packages/amplify-graphql-transformer-core/src/transformer-context/index.ts b/packages/amplify-graphql-transformer-core/src/transformer-context/index.ts index 59f32bab104..266dc3a4f79 100644 --- a/packages/amplify-graphql-transformer-core/src/transformer-context/index.ts +++ b/packages/amplify-graphql-transformer-core/src/transformer-context/index.ts @@ -5,7 +5,9 @@ import { TransformerContextOutputProvider, TransformerContextProvider, TransformerDataSourceManagerProvider, + AppSyncAuthConfiguration, } from '@aws-amplify/graphql-transformer-interfaces'; +import { TransformerContextMetadataProvider } from '@aws-amplify/graphql-transformer-interfaces/src/transformer-context/transformer-context-provider'; import { App } from '@aws-cdk/core'; import { DocumentNode } from 'graphql'; import { ResolverConfig } from '../config/transformer-config'; @@ -17,6 +19,25 @@ import { TransformerContextProviderRegistry } from './provider-registry'; import { ResolverManager } from './resolver'; import { TransformerResourceHelper } from './resource-helper'; import { StackManager } from './stack-manager'; +export { TransformerResolver } from './resolver'; +export class TransformerContextMetadata implements TransformerContextMetadataProvider { + /** + * Used by transformers to pass information between one another. + */ + private metadata: { [key: string]: any } = new Map(); + + public get(key: string): T | undefined { + return this.metadata[key] as T; + } + + public set(key: string, val: T): void { + this.metadata[key] = val; + } + + public has(key: string) { + return this.metadata[key] !== undefined; + } +} export class TransformerContext implements TransformerContextProvider { public readonly output: TransformerContextOutputProvider; @@ -27,12 +48,15 @@ export class TransformerContext implements TransformerContextProvider { public readonly resourceHelper: TransformerResourceHelper; public readonly featureFlags: FeatureFlagProvider; public _api?: GraphQLAPIProvider; + public readonly authConfig: AppSyncAuthConfiguration; private resolverConfig: ResolverConfig | undefined; + public metadata: TransformerContextMetadata; constructor( app: App, public readonly inputDocument: DocumentNode, stackMapping: Record, + authConfig: AppSyncAuthConfiguration, featureFlags?: FeatureFlagProvider, resolverConfig?: ResolverConfig, ) { @@ -42,9 +66,11 @@ export class TransformerContext implements TransformerContextProvider { this.providerRegistry = new TransformerContextProviderRegistry(); const stackManager = new StackManager(app, stackMapping); this.stackManager = stackManager; + this.authConfig = authConfig; this.resourceHelper = new TransformerResourceHelper(stackManager); this.featureFlags = featureFlags ?? new NoopFeatureFlagProvider(); this.resolverConfig = resolverConfig; + this.metadata = new TransformerContextMetadata(); } /** diff --git a/packages/amplify-graphql-transformer-core/src/transformer-context/resolver.ts b/packages/amplify-graphql-transformer-core/src/transformer-context/resolver.ts index ec0dc0059ba..00e8128bd0a 100644 --- a/packages/amplify-graphql-transformer-core/src/transformer-context/resolver.ts +++ b/packages/amplify-graphql-transformer-core/src/transformer-context/resolver.ts @@ -7,13 +7,14 @@ import { TransformerResolverProvider, TransformerResolversManagerProvider, } from '@aws-amplify/graphql-transformer-interfaces'; -import { CfnFunctionConfiguration } from '@aws-cdk/aws-appsync'; -import { isResolvableObject, Stack } from '@aws-cdk/core'; +import { AuthorizationType, CfnFunctionConfiguration } from '@aws-cdk/aws-appsync'; +import { isResolvableObject, Stack, CfnParameter } from '@aws-cdk/core'; import assert from 'assert'; import { toPascalCase } from 'graphql-transformer-common'; import { dedent } from 'ts-dedent'; import { MappingTemplate, S3MappingTemplate } from '../cdk-compat'; import * as SyncUtils from '../transformation/sync-utils'; +import { IAM_AUTH_ROLE_PARAMETER, IAM_UNAUTH_ROLE_PARAMETER } from '../utils'; import { StackManager } from './stack-manager'; type Slot = { @@ -95,6 +96,11 @@ export class ResolverManager implements TransformerResolversManagerProvider { } }; + hasResolver = (typeName: string, fieldName: string): boolean => { + const key = `${typeName}.${fieldName}`; + return this.resolvers.has(key); + }; + removeResolver = (typeName: string, fieldName: string): TransformerResolverProvider => { const key = `${typeName}.${fieldName}`; if (this.resolvers.has(key)) { @@ -234,24 +240,38 @@ export class TransformerResolver implements TransformerResolverProvider { } break; default: - throw new Error('Unknow DataSource type'); + throw new Error('Unknown DataSource type'); } } + let initResolver = dedent` + $util.qr($ctx.stash.put("typeName", "${this.typeName}")) + $util.qr($ctx.stash.put("fieldName", "${this.fieldName}")) + $util.qr($ctx.stash.put("conditions", [])) + $util.qr($ctx.stash.put("metadata", {})) + $util.qr($ctx.stash.metadata.put("dataSourceType", "${dataSourceType}")) + $util.qr($ctx.stash.metadata.put("apiId", "${api.apiId}")) + ${dataSource} + `; + const authModes = [context.authConfig.defaultAuthentication, ...(context.authConfig.additionalAuthenticationProviders || [])].map( + mode => mode?.authenticationType, + ); + if (authModes.includes(AuthorizationType.IAM)) { + const authRoleParameter = (context.stackManager.getParameter(IAM_AUTH_ROLE_PARAMETER) as CfnParameter).valueAsString; + const unauthRoleParameter = (context.stackManager.getParameter(IAM_UNAUTH_ROLE_PARAMETER) as CfnParameter).valueAsString; + initResolver += dedent`\n + $util.qr($ctx.stash.put("authRole", "arn:aws:sts::${ + Stack.of(context.stackManager.rootStack).account + }:assumed-role/${authRoleParameter}/CognitoIdentityCredentials")) + $util.qr($ctx.stash.put("unauthRole", "arn:aws:sts::${ + Stack.of(context.stackManager.rootStack).account + }:assumed-role/${unauthRoleParameter}/CognitoIdentityCredentials")) + `; + } + initResolver += '\n$util.toJson({})'; api.host.addResolver( this.typeName, this.fieldName, - MappingTemplate.inlineTemplateFromString( - dedent` - $util.qr($ctx.stash.put("typeName", "${this.typeName}")) - $util.qr($ctx.stash.put("fieldName", "${this.fieldName}")) - $util.qr($ctx.stash.put("conditions", [])) - $util.qr($ctx.stash.put("metadata", {})) - $util.qr($ctx.stash.metadata.put("dataSourceType", "${dataSourceType}")) - $util.qr($ctx.stash.metadata.put("apiId", "${api.apiId}")) - ${dataSource} - $util.toJson({}) - `, - ), + MappingTemplate.inlineTemplateFromString(initResolver), MappingTemplate.inlineTemplateFromString('$util.toJson($ctx.prev.result)'), undefined, [...requestFns, dataSourceProviderFn, ...responseFns].map(fn => fn.functionId), diff --git a/packages/amplify-graphql-transformer-core/src/transformer-context/stack-manager.ts b/packages/amplify-graphql-transformer-core/src/transformer-context/stack-manager.ts index 003f41ec957..40faf98fe1c 100644 --- a/packages/amplify-graphql-transformer-core/src/transformer-context/stack-manager.ts +++ b/packages/amplify-graphql-transformer-core/src/transformer-context/stack-manager.ts @@ -23,6 +23,7 @@ export class StackManager implements StackManagerProvider { } createStack = (stackName: string): Stack => { const newStack = new TransformerNestedStack(this.rootStack, stackName); + this.stacks.set(stackName, newStack); return newStack; }; diff --git a/packages/amplify-graphql-transformer-core/src/utils/authType.ts b/packages/amplify-graphql-transformer-core/src/utils/authType.ts index 2be8d32a082..945da6dd5db 100644 --- a/packages/amplify-graphql-transformer-core/src/utils/authType.ts +++ b/packages/amplify-graphql-transformer-core/src/utils/authType.ts @@ -1,8 +1,8 @@ import { AuthorizationConfig, AuthorizationMode, AuthorizationType } from '@aws-cdk/aws-appsync'; import { UserPool } from '@aws-cdk/aws-cognito'; import { Duration, Expiration } from '@aws-cdk/core'; -import { AppSyncAuthConfiguration, AppSyncAuthConfigurationEntry, AppSyncAuthMode } from '../config'; import { StackManager } from '../transformer-context/stack-manager'; +import { AppSyncAuthConfiguration, AppSyncAuthConfigurationEntry, AppSyncAuthMode } from '@aws-amplify/graphql-transformer-interfaces'; const authTypeMap: Record = { API_KEY: AuthorizationType.API_KEY, @@ -10,6 +10,10 @@ const authTypeMap: Record = { AWS_IAM: AuthorizationType.IAM, OPENID_CONNECT: AuthorizationType.OIDC, }; + +export const IAM_AUTH_ROLE_PARAMETER = 'authRoleName'; +export const IAM_UNAUTH_ROLE_PARAMETER = 'unauthRoleName'; + export function adoptAuthModes(stack: StackManager, authConfig: AppSyncAuthConfiguration): AuthorizationConfig { return { defaultAuthorization: adoptAuthMode(stack, authConfig.defaultAuthentication), @@ -24,8 +28,10 @@ export function adoptAuthMode(stackManager: StackManager, entry: AppSyncAuthConf return { authorizationType: authType, apiKeyConfig: { - description: entry.apiKeyConfig.description, - expires: Expiration.after(Duration.days(entry.apiKeyConfig.apiKeyExpirationDays)), + description: entry.apiKeyConfig?.description, + expires: entry.apiKeyConfig?.apiKeyExpirationDays + ? Expiration.after(Duration.days(entry.apiKeyConfig.apiKeyExpirationDays)) + : undefined, }, }; case AuthorizationType.USER_POOL: diff --git a/packages/amplify-graphql-transformer-core/src/utils/index.ts b/packages/amplify-graphql-transformer-core/src/utils/index.ts index ab2e7da49c9..d8170ab56cb 100644 --- a/packages/amplify-graphql-transformer-core/src/utils/index.ts +++ b/packages/amplify-graphql-transformer-core/src/utils/index.ts @@ -2,3 +2,5 @@ export { DirectiveWrapper } from './directive-wrapper'; export { collectDirectives, collectDirectivesByTypeNames } from './type-map-utils'; export { stripDirectives } from './strip-directives'; export { DEFAULT_SCHEMA_DEFINITION } from './defaultSchema'; +export { getSandboxModeEnvNameFromNodeMap, getSandboxModeEnvNameFromDirectiveSet } from './sandbox-mode'; +export { IAM_AUTH_ROLE_PARAMETER, IAM_UNAUTH_ROLE_PARAMETER } from './authType'; diff --git a/packages/amplify-graphql-transformer-core/src/utils/sandbox-mode.ts b/packages/amplify-graphql-transformer-core/src/utils/sandbox-mode.ts new file mode 100644 index 00000000000..d580b53ce35 --- /dev/null +++ b/packages/amplify-graphql-transformer-core/src/utils/sandbox-mode.ts @@ -0,0 +1,16 @@ +export function getSandboxModeEnvNameFromNodeMap(input: any): string { + const ampGlobalType: any = input.AMPLIFY_GLOBAL; + + if (!ampGlobalType) return ''; + + return getSandboxModeEnvNameFromDirectiveSet(ampGlobalType.directives); +} + +export function getSandboxModeEnvNameFromDirectiveSet(input: any): string { + const sandboxModeDirective = input.find((el: any) => el.name.value === 'allow_public_data_access_with_api_key'); + + if (!sandboxModeDirective) return ''; + + const inField = sandboxModeDirective.arguments.find((el: any) => el.name.value === 'in'); + return inField.value.value; +} diff --git a/packages/amplify-graphql-transformer-interfaces/src/graphql-api-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/graphql-api-provider.ts index 4e7ce993724..6514c3e48a0 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/graphql-api-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/graphql-api-provider.ts @@ -1,6 +1,51 @@ import { CfnResource, Construct, IAsset, IConstruct } from '@aws-cdk/core'; import { Grant, IGrantable, IRole } from '@aws-cdk/aws-iam'; -import {TransformHostProvider} from './transform-host-provider'; +import { TransformHostProvider } from './transform-host-provider'; + +// Auth Config +export type AppSyncAuthMode = 'API_KEY' | 'AMAZON_COGNITO_USER_POOLS' | 'AWS_IAM' | 'OPENID_CONNECT'; +export type AppSyncAuthConfiguration = { + defaultAuthentication: AppSyncAuthConfigurationEntry; + additionalAuthenticationProviders: Array; +}; + +export type AppSyncAuthConfigurationEntry = + | AppSyncAuthConfigurationUserPoolEntry + | AppSyncAuthConfigurationAPIKeyEntry + | AppSyncAuthConfigurationIAMEntry + | AppSyncAuthConfigurationOIDCEntry; +export type AppSyncAuthConfigurationAPIKeyEntry = { + authenticationType: 'API_KEY'; + apiKeyConfig?: ApiKeyConfig; +}; +export type AppSyncAuthConfigurationUserPoolEntry = { + authenticationType: 'AMAZON_COGNITO_USER_POOLS'; + userPoolConfig?: UserPoolConfig; +}; +export type AppSyncAuthConfigurationIAMEntry = { + authenticationType: 'AWS_IAM'; +}; + +export type AppSyncAuthConfigurationOIDCEntry = { + authenticationType: 'OPENID_CONNECT'; + openIDConnectConfig?: OpenIDConnectConfig; +}; + +export interface ApiKeyConfig { + description?: string; + apiKeyExpirationDays: number; + apiKeyExpirationDate?: Date; +} +export interface UserPoolConfig { + userPoolId: string; +} +export interface OpenIDConnectConfig { + name: string; + issuerUrl: string; + clientId?: string; + iatTTL?: number; + authTTL?: number; +} export interface AppSyncFunctionConfigurationProvider extends IConstruct { readonly arn: string; diff --git a/packages/amplify-graphql-transformer-interfaces/src/index.ts b/packages/amplify-graphql-transformer-interfaces/src/index.ts index 5271dfc2c34..36be2b3a84a 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/index.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/index.ts @@ -21,8 +21,9 @@ export { MutationFieldType, QueryFieldType, SubscriptionFieldType, - TransformerModelEnhancementProvider, TransformerModelProvider, + TransformerModelEnhancementProvider, + TransformerAuthProvider, } from './transformer-model-provider'; export { FeatureFlagProvider } from './feature-flag-provider'; @@ -36,6 +37,15 @@ export { InlineMappingTemplateProvider, APIIAMResourceProvider, TemplateType as MappingTemplateType, + AppSyncAuthConfiguration, + AppSyncAuthConfigurationAPIKeyEntry, + AppSyncAuthConfigurationEntry, + AppSyncAuthConfigurationIAMEntry, + ApiKeyConfig, + AppSyncAuthConfigurationOIDCEntry, + AppSyncAuthConfigurationUserPoolEntry, + AppSyncAuthMode, + UserPoolConfig, } from './graphql-api-provider'; export { TransformHostProvider, DynamoDbDataSourceOptions } from './transform-host-provider'; diff --git a/packages/amplify-graphql-transformer-interfaces/src/transform-host-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transform-host-provider.ts index 6ef36c63475..de89ebcea1b 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transform-host-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transform-host-provider.ts @@ -73,4 +73,7 @@ export interface TransformHostProvider { getDataSource: (name: string) => BaseDataSource | void; hasDataSource: (name: string) => boolean; + + getResolver: (typeName: string, fieldName: string) => CfnResolver | void; + hasResolver: (typeName: string, fieldName: string) => boolean; } diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/stack-manager-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/stack-manager-provider.ts index b528c7eeec1..70d1e23842b 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/stack-manager-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/stack-manager-provider.ts @@ -1,6 +1,7 @@ import { CfnParameter, CfnParameterProps, Stack } from '@aws-cdk/core'; export interface StackManagerProvider { + readonly rootStack: Stack; getStack: (stackName: string) => Stack; createStack: (stackName: string) => Stack; hasStack: (stackName: string) => boolean; diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-context-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-context-provider.ts index afaa8317841..1d3c41c133e 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-context-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-context-provider.ts @@ -4,11 +4,18 @@ import { TransformerProviderRegistry } from './transformer-provider-registry'; import { DocumentNode } from 'graphql'; import { TransformerContextOutputProvider } from './transformer-context-output-provider'; import { StackManagerProvider } from './stack-manager-provider'; -import { GraphQLAPIProvider } from '../graphql-api-provider'; +import { AppSyncAuthConfiguration, GraphQLAPIProvider } from '../graphql-api-provider'; import { TransformerResourceProvider } from './resource-resource-provider'; import { FeatureFlagProvider } from '../feature-flag-provider'; +export interface TransformerContextMetadataProvider { + set(key: string, value: T): void; + get(key: string): T | undefined; + has(key: string): boolean; +} + export interface TransformerContextProvider { + metadata: TransformerContextMetadataProvider; resolvers: TransformerResolversManagerProvider; dataSources: TransformerDataSourceManagerProvider; providerRegistry: TransformerProviderRegistry; @@ -19,6 +26,7 @@ export interface TransformerContextProvider { api: GraphQLAPIProvider; resourceHelper: TransformerResourceProvider; featureFlags: FeatureFlagProvider; + authConfig: AppSyncAuthConfiguration; isProjectUsingDataStore(): boolean; getResolverConfig(): ResolverConfig | undefined; @@ -26,15 +34,30 @@ export interface TransformerContextProvider { export type TransformerBeforeStepContextProvider = Pick< TransformerContextProvider, - 'inputDocument' | 'featureFlags' | 'isProjectUsingDataStore' + 'inputDocument' | 'featureFlags' | 'isProjectUsingDataStore' | 'getResolverConfig' | 'authConfig' >; export type TransformerSchemaVisitStepContextProvider = Pick< TransformerContextProvider, - 'inputDocument' | 'output' | 'providerRegistry' | 'featureFlags' | 'isProjectUsingDataStore' | 'getResolverConfig' + | 'inputDocument' + | 'output' + | 'providerRegistry' + | 'featureFlags' + | 'isProjectUsingDataStore' + | 'getResolverConfig' + | 'metadata' + | 'authConfig' >; export type TransformerValidationStepContextProvider = Pick< TransformerContextProvider, - 'inputDocument' | 'output' | 'providerRegistry' | 'dataSources' | 'featureFlags' | 'isProjectUsingDataStore' | 'getResolverConfig' + | 'inputDocument' + | 'output' + | 'providerRegistry' + | 'dataSources' + | 'featureFlags' + | 'isProjectUsingDataStore' + | 'getResolverConfig' + | 'metadata' + | 'authConfig' >; export type TransformerPrepareStepContextProvider = TransformerValidationStepContextProvider; export type TransformerTransformSchemaStepContextProvider = TransformerValidationStepContextProvider; diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-datasource-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-datasource-provider.ts index c1472951639..8350f8be702 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-datasource-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-datasource-provider.ts @@ -22,6 +22,7 @@ export type DataSourceInstance = ITable | CfnDomain | HttpDataSource | IFunction export interface TransformerDataSourceManagerProvider { add(type: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, dataSourceInstance: DataSourceInstance): void; get(type: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): DataSourceInstance; + has(name: string): boolean; } export interface DataSourceProvider extends BackedDataSource {} diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-resolver-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-resolver-provider.ts index 2688c9c192b..b369c6bb234 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-resolver-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-context/transformer-resolver-provider.ts @@ -17,6 +17,7 @@ export interface TransformerResolverProvider { export interface TransformerResolversManagerProvider { addResolver: (typeName: string, fieldName: string, resolver: TransformerResolverProvider) => TransformerResolverProvider; getResolver: (typeName: string, fieldName: string) => TransformerResolverProvider | void; + hasResolver: (typeName: string, fieldName: string) => boolean; removeResolver: (typeName: string, fieldName: string) => TransformerResolverProvider; collectResolvers: () => Map; diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-model-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-model-provider.ts index 9bf6090705e..ee5d4372e67 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-model-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-model-provider.ts @@ -129,4 +129,6 @@ export interface TransformerModelProvider extends TransformerPluginProvider { ) => ObjectTypeDefinitionNode; } +export interface TransformerAuthProvider extends TransformerPluginProvider {} + export interface TransformerModelEnhancementProvider extends Partial {} diff --git a/packages/amplify-graphql-transformer-interfaces/src/transformer-plugin-provider.ts b/packages/amplify-graphql-transformer-interfaces/src/transformer-plugin-provider.ts index e506f490beb..076831255b5 100644 --- a/packages/amplify-graphql-transformer-interfaces/src/transformer-plugin-provider.ts +++ b/packages/amplify-graphql-transformer-interfaces/src/transformer-plugin-provider.ts @@ -25,6 +25,7 @@ export enum TransformerPluginType { DATA_SOURCE_PROVIDER = 'DATA_SOURCE_PROVIDER', DATA_SOURCE_ENHANCER = 'DATA_SOURCE_ENHANCER', GENERIC = 'GENERIC', + AUTH = 'AUTH', } export interface TransformerPluginProvider { pluginType: TransformerPluginType; diff --git a/packages/amplify-headless-interface/src/interface/api/add.ts b/packages/amplify-headless-interface/src/interface/api/add.ts index 51f44124538..081eaf07e57 100644 --- a/packages/amplify-headless-interface/src/interface/api/add.ts +++ b/packages/amplify-headless-interface/src/interface/api/add.ts @@ -130,6 +130,7 @@ export type AppSyncAuthType = export interface AppSyncAPIKeyAuthType { mode: 'API_KEY'; expirationTime?: number; + apiKeyExpirationDate?: Date; keyDescription?: string; } diff --git a/packages/amplify-provider-awscloudformation/package.json b/packages/amplify-provider-awscloudformation/package.json index d596905d921..ea5ee39ea68 100644 --- a/packages/amplify-provider-awscloudformation/package.json +++ b/packages/amplify-provider-awscloudformation/package.json @@ -24,6 +24,7 @@ "watch": "tsc --watch" }, "dependencies": { + "@aws-amplify/graphql-auth-transformer": "0.1.0", "@aws-amplify/graphql-function-transformer": "0.4.4", "@aws-amplify/graphql-http-transformer": "0.5.4", "@aws-amplify/graphql-index-transformer": "0.3.3", diff --git a/packages/amplify-provider-awscloudformation/src/graphql-transformer/transform-graphql-schema.ts b/packages/amplify-provider-awscloudformation/src/graphql-transformer/transform-graphql-schema.ts index 3c510bc595e..2cf6fdd6459 100644 --- a/packages/amplify-provider-awscloudformation/src/graphql-transformer/transform-graphql-schema.ts +++ b/packages/amplify-provider-awscloudformation/src/graphql-transformer/transform-graphql-schema.ts @@ -3,14 +3,17 @@ import path from 'path'; import importGlobal from 'import-global'; import { print } from 'graphql'; import importFrom from 'import-from'; -import { TransformerPluginProvider } from '@aws-amplify/graphql-transformer-interfaces'; +import { TransformerPluginProvider, AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; import { getAppSyncServiceExtraDirectives, GraphQLTransform, collectDirectivesByTypeNames, + collectDirectives, TransformerProjectConfig, + getSandboxModeEnvNameFromDirectiveSet, } from '@aws-amplify/graphql-transformer-core'; import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; import { FunctionTransformer } from '@aws-amplify/graphql-function-transformer'; import { HttpTransformer } from '@aws-amplify/graphql-http-transformer'; import { PredictionsTransformer } from '@aws-amplify/graphql-predictions-transformer'; @@ -25,15 +28,15 @@ import { SearchableModelTransformer } from '@aws-amplify/graphql-searchable-tran import { DefaultValueTransformer } from '@aws-amplify/graphql-default-value-transformer'; import { ProviderName as providerName } from '../constants'; import { hashDirectory } from '../upload-appsync-files'; -import { mergeUserConfigWithTransformOutput, writeDeploymentToDisk } from './utils'; +import { mergeUserConfigWithTransformOutput, writeDeploymentToDisk, showACM } from './utils'; import { loadProject as readTransformerConfiguration } from './transform-config'; import { loadProject } from 'graphql-transformer-core'; -import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-core'; import { Template } from '@aws-amplify/graphql-transformer-core/lib/config/project-config'; import { AmplifyCLIFeatureFlagAdapter } from '../utils/amplify-cli-feature-flag-adapter'; -import { JSONUtilities } from 'amplify-cli-core'; +import { JSONUtilities, stateManager, $TSContext } from 'amplify-cli-core'; import { searchablePushChecks } from '../transform-graphql-schema'; import { ResourceConstants } from 'graphql-transformer-common'; +import { isAmplifyAdminApp } from '../utils/admin-helpers'; const API_CATEGORY = 'api'; const STORAGE_CATEGORY = 'storage'; @@ -55,7 +58,10 @@ function warnOnAuth(context, map) { } } -function getTransformerFactory(context, resourceDir) { +function getTransformerFactory( + context: $TSContext, + resourceDir: string, +): (options: TransformerFactoryArgs) => Promise { return async (options?: TransformerFactoryArgs) => { const modelTransformer = new ModelTransformer(); const indexTransformer = new IndexTransformer(); @@ -147,7 +153,19 @@ function getTransformerFactory(context, resourceDir) { // TODO: Build dependency mechanism into transformers. Auth runs last // so any resolvers that need to be protected will already be created. - // transformerList.push(new ModelAuthTransformer({ authConfig })); + + let amplifyAdminEnabled: boolean = false; + let adminUserPoolID: string; + try { + const amplifyMeta = stateManager.getMeta(); + const appId = amplifyMeta?.providers?.[providerName]?.AmplifyAppId; + const res = await isAmplifyAdminApp(appId); + amplifyAdminEnabled = res.isAdminApp; + adminUserPoolID = res.userPoolID; + } catch (err) { + console.info('App not deployed yet.'); + } + transformerList.push(new AuthTransformer({ authConfig: options?.authConfig, addAwsIamAuthInOutputSchema: false, adminUserPoolID })); return transformerList; }; @@ -224,7 +242,7 @@ export async function transformGraphQLSchema(context, options) { } } - let { authConfig } = options; + let { authConfig }: { authConfig: AppSyncAuthConfiguration } = options; // // If we don't have an authConfig from the caller, use it from the @@ -272,6 +290,11 @@ export async function transformGraphQLSchema(context, options) { const project = await loadProject(resourceDir); + if (flags['acm']) { + showACM(project.schema, flags['acm']); + return; + } + const lastDeployedProjectConfig = fs.existsSync(previouslyDeployedBackendDir) ? await loadProject(previouslyDeployedBackendDir) : undefined; @@ -283,6 +306,8 @@ export async function transformGraphQLSchema(context, options) { const transformerListFactory = getTransformerFactory(context, resourceDir); + const sandboxModeEnv = getSandboxModeEnvNameFromDirectiveSet(collectDirectives(project.schema)); + let searchableTransformerFlag = false; if (directiveMap.directives.includes('searchable')) { @@ -294,13 +319,14 @@ export async function transformGraphQLSchema(context, options) { buildParameters, projectDirectory: resourceDir, transformersFactory: transformerListFactory, - transformersFactoryArgs: { addSearchableTransformer: searchableTransformerFlag, storageConfig }, + transformersFactoryArgs: { addSearchableTransformer: searchableTransformerFlag, storageConfig, authConfig }, rootStackFileName: 'cloudformation-template.json', currentCloudBackendDirectory: previouslyDeployedBackendDir, minify: options.minify, projectConfig: project, lastDeployedProjectConfig, authConfig, + sandboxModeEnv, }; let transformerOutput; @@ -371,8 +397,8 @@ async function getPreviousDeploymentRootKey(previouslyDeployedBackendDir) { } } -export async function getDirectiveDefinitions(context, resourceDir) { - const transformList = await getTransformerFactory(context, resourceDir)({ addSearchableTransformer: true }); +export async function getDirectiveDefinitions(context: $TSContext, resourceDir: string) { + const transformList = await getTransformerFactory(context, resourceDir)({ addSearchableTransformer: true, authConfig: {} }); const appSynDirectives = getAppSyncServiceExtraDirectives(); const transformDirectives = transformList .map(transformPluginInst => [transformPluginInst.directive, ...transformPluginInst.typeDefinitions].map(node => print(node)).join('\n')) @@ -419,6 +445,7 @@ function getBucketName(context, s3ResourceName, backEndDir) { type TransformerFactoryArgs = { addSearchableTransformer: boolean; + authConfig: any; storageConfig?: any; }; export type ProjectOptions = { @@ -427,7 +454,7 @@ export type ProjectOptions = { S3DeploymentRootKey: string; }; projectDirectory?: string; - transformersFactory: (options: T) => TransformerPluginProvider[]; + transformersFactory: (options: T) => Promise; transformersFactoryArgs: T; rootStackFileName: 'cloudformation-template.json'; currentCloudBackendDirectory: string; @@ -437,6 +464,7 @@ export type ProjectOptions = { dryRun?: boolean; authConfig?: AppSyncAuthConfiguration; stacks: Record; + sandboxModeEnv?: string; }; export async function buildAPIProject(opts: ProjectOptions) { @@ -454,6 +482,9 @@ export async function buildAPIProject(opts: ProjectOptions node.kind === 'ObjectTypeDefinition' && node.name.value === nodeName && node.directives.find(dir => dir.name.value === 'model'), + ) as ObjectTypeDefinitionNode; + if (!type) { + throw new Error(`${nodeName} does not have @model`); + } else { + const fields: string[] = type.fields!.map((field: FieldDefinitionNode) => field.name.value); + const acm = new AccessControlMatrix({ operations: MODEL_OPERATIONS, resources: fields }); + const parentAuthDirective = type.directives?.find(dir => dir.name.value === 'auth'); + if (parentAuthDirective) { + const authRules = getAuthRulesFromDirective(parentAuthDirective); + ensureAuthRuleDefaults(authRules); + convertModelRulesToRoles(acm, authRules); + } + for (let fieldNode of type.fields || []) { + let fieldAuthDir = fieldNode.directives?.find(dir => dir.name.value === 'auth') as DirectiveNode; + if (fieldAuthDir) { + if (parentAuthDirective) { + acm.resetAccessForResource(fieldNode.name.value); + } + let fieldAuthRules = getAuthRulesFromDirective(fieldAuthDir); + ensureAuthRuleDefaults(fieldAuthRules); + convertModelRulesToRoles(acm, fieldAuthRules, fieldNode.name.value); + } + } + const truthTable = acm.getAcmPerRole(); + for (let [role, acm] of truthTable) { + console.group(role); + console.table(acm); + console.groupEnd(); + } + } +} +// helper functions for setting up acm +function getAuthRulesFromDirective(directive: DirectiveNode) { + const get = (s: string) => (arg: ArgumentNode) => arg.name.value === s; + const getArg = (arg: string, dflt?: any) => { + const argument = directive.arguments?.find(get(arg)); + return argument ? valueFromASTUntyped(argument.value) : dflt; + }; + + // Get and validate the auth rules. + const authRules = getArg('rules', []) as AuthRule[]; + + // All the IAM auth rules that are added using @auth directive need IAM policy to be generated. AuthRules added for AdminUI don't + return authRules.map(rule => (rule.provider === 'iam' ? { ...rule, generateIAMPolicy: true } : rule)); +} + +function ensureAuthRuleDefaults(rules: AuthRule[]) { + // We assign the default provider if an override is not present make further handling easier. + for (const rule of rules) { + if (!rule.provider) { + switch (rule.allow) { + case 'owner': + case 'groups': + rule.provider = 'userPools'; + break; + case 'private': + rule.provider = 'userPools'; + break; + case 'public': + rule.provider = 'apiKey'; + break; + default: + rule.provider = null; + break; + } + } + if (rule.provider === 'iam') { + rule.generateIAMPolicy = true; + } + } +} +function convertModelRulesToRoles(acm: AccessControlMatrix, authRules: AuthRule[], field?: string) { + for (let rule of authRules) { + let operations: ModelOperation[] = rule.operations || MODEL_OPERATIONS; + if (rule.groups && !rule.groupsField) { + rule.groups.forEach(group => { + let roleName = `${rule.provider}:staticGroup:${group}`; + acm.setRole({ role: roleName, resource: field, operations }); + }); + } else { + let roleName: string; + switch (rule.provider) { + case 'apiKey': + roleName = 'apiKey:public'; + break; + case 'iam': + roleName = `iam:${rule.allow}`; + break; + case 'oidc': + case 'userPools': + if (rule.allow === 'groups') { + let groupsField = rule.groupsField || DEFAULT_GROUPS_FIELD; + roleName = `${rule.provider}:dynamicGroup:${groupsField}`; + } else if (rule.allow === 'owner') { + let ownerField = rule.ownerField || DEFAULT_OWNER_FIELD; + roleName = `${rule.provider}:owner:${ownerField}`; + } else if (rule.allow === 'private') { + roleName = `${rule.provider}:${rule.allow}`; + } else { + throw new Error(`Could not create a role from ${JSON.stringify(rule)}`); + } + break; + default: + throw new Error(`Could not create a role from ${JSON.stringify(rule)}`); + } + acm.setRole({ role: roleName, resource: field, operations }); + } + } +} diff --git a/packages/amplify-provider-awscloudformation/src/utils/admin-helpers.ts b/packages/amplify-provider-awscloudformation/src/utils/admin-helpers.ts index 0cd6143c3db..13c24707899 100644 --- a/packages/amplify-provider-awscloudformation/src/utils/admin-helpers.ts +++ b/packages/amplify-provider-awscloudformation/src/utils/admin-helpers.ts @@ -17,7 +17,7 @@ export function doAdminTokensExist(appId: string): boolean { return !!stateManager.getAmplifyAdminConfigEntry(appId); } -export async function isAmplifyAdminApp(appId: string): Promise<{ isAdminApp: boolean; region: string }> { +export async function isAmplifyAdminApp(appId: string): Promise<{ isAdminApp: boolean; region: string; userPoolID: string }> { if (!appId) { throw `Failed to check if Admin UI is enabled: appId is undefined`; } @@ -25,7 +25,8 @@ export async function isAmplifyAdminApp(appId: string): Promise<{ isAdminApp: bo if (appState.appId && appState.region && appState.region !== 'us-east-1') { appState = await getAdminAppState(appId, appState.region); } - return { isAdminApp: !!appState.appId, region: appState.region }; + const userPoolID = appState.loginAuthConfig ? JSON.parse(appState.loginAuthConfig).aws_user_pools_id : ''; + return { isAdminApp: !!appState.appId, region: appState.region, userPoolID }; } export async function getTempCredsWithAdminTokens(context: $TSContext, appId: string): Promise { diff --git a/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts b/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts index cf2fab44ac3..6e41670abd6 100644 --- a/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts +++ b/packages/graphql-auth-transformer/src/ModelAuthTransformer.ts @@ -98,6 +98,7 @@ export type AppSyncAuthConfigurationEntry = { export type ApiKeyConfig = { description?: string; apiKeyExpirationDays: number; + apiKeyExpirationDate?: Date; }; export type UserPoolConfig = { userPoolId: string; @@ -1387,9 +1388,8 @@ operations will be generated by the CLI.`, // In create mutations, the dynamic group and ownership authorization checks // are done before calling PutItem. - const dynamicGroupAuthorizationExpression = this.resources.dynamicGroupAuthorizationExpressionForCreateOperations( - dynamicGroupAuthorizationRules, - ); + const dynamicGroupAuthorizationExpression = + this.resources.dynamicGroupAuthorizationExpressionForCreateOperations(dynamicGroupAuthorizationRules); const fieldIsList = (fieldName: string) => { const field = parent.fields.find(field => field.name.value === fieldName); if (field) { @@ -1547,9 +1547,8 @@ operations will be generated by the CLI.`, ]), ); - const throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty = this.resources.throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty( - field, - ); + const throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty = + this.resources.throwIfNotStaticGroupAuthorizedOrAuthConditionIsEmpty(field); // If we've any modes to check, then add the authMode check code block // to the start of the resolver. diff --git a/packages/graphql-mapping-template/src/print.ts b/packages/graphql-mapping-template/src/print.ts index bd5a90f853c..b871264e156 100644 --- a/packages/graphql-mapping-template/src/print.ts +++ b/packages/graphql-mapping-template/src/print.ts @@ -115,7 +115,7 @@ function printReference(node: ReferenceNode): string { } function printQuietReference(node: QuietReferenceNode, indent: string = ''): string { - const val = typeof node.value === 'string' ? node.value : printExpr(node.value) + const val = typeof node.value === 'string' ? node.value : printExpr(node.value); return `${indent}$util.qr(${val})`; } diff --git a/packages/graphql-transformers-e2e-tests/package.json b/packages/graphql-transformers-e2e-tests/package.json index 220c05dd663..14049ed8130 100644 --- a/packages/graphql-transformers-e2e-tests/package.json +++ b/packages/graphql-transformers-e2e-tests/package.json @@ -35,6 +35,7 @@ "@aws-amplify/graphql-model-transformer": "0.6.3", "@aws-amplify/graphql-transformer-core": "0.9.1", "@aws-amplify/graphql-default-value-transformer" : "0.1.0", + "@aws-amplify/graphql-transformer-interfaces": "1.9.1", "@types/node": "^12.12.6", "aws-amplify": "^4.2.8", "aws-appsync": "^4.1.1", diff --git a/packages/graphql-transformers-e2e-tests/src/__tests__/AuthV2Transformer.e2e.test.ts b/packages/graphql-transformers-e2e-tests/src/__tests__/AuthV2Transformer.e2e.test.ts new file mode 100644 index 00000000000..5721d076abd --- /dev/null +++ b/packages/graphql-transformers-e2e-tests/src/__tests__/AuthV2Transformer.e2e.test.ts @@ -0,0 +1,3329 @@ +import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; +import { HasOneTransformer } from '@aws-amplify/graphql-relational-transformer'; +import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; +import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; +import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; +import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; +import { Output } from 'aws-sdk/clients/cloudformation'; +import { CloudFormationClient } from '../CloudFormationClient'; +import { S3Client } from '../S3Client'; +import { cleanupStackAfterTest, deploy } from '../deployNestedStacks'; +import { default as CognitoClient } from 'aws-sdk/clients/cognitoidentityserviceprovider'; +import { default as S3 } from 'aws-sdk/clients/s3'; +import moment from 'moment'; +import { + createUserPool, + createUserPoolClient, + configureAmplify, + addUserToGroup, + authenticateUser, + createGroup, + signupUser, +} from '../cognitoUtils'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { GraphQLClient } from '../GraphQLClient'; + +jest.setTimeout(2000000); + +describe('@model with @auth', () => { + // setup clients + const cf = new CloudFormationClient('us-west-2'); + const customS3Client = new S3Client('us-west-2'); + const cognitoClient = new CognitoClient({ apiVersion: '2016-04-19', region: 'us-west-2' }); + const awsS3Client = new S3({ region: 'us-west-2' }); + + // stack info + const BUILD_TIMESTAMP = moment().format('YYYYMMDDHHmmss'); + const STACK_NAME = `AuthV2TransformerTests-${BUILD_TIMESTAMP}`; + const BUCKET_NAME = `appsync-auth-v2-transformer-test-bucket-${BUILD_TIMESTAMP}`; + const LOCAL_FS_BUILD_DIR = '/tmp/authv2_transformer_tests/'; + const S3_ROOT_DIR_KEY = 'deployments'; + let USER_POOL_ID: string; + let GRAPHQL_ENDPOINT: string; + /** + * Client 1 is logged in and is a member of the Admin group. + */ + let GRAPHQL_CLIENT_1: GraphQLClient; + + /** + * Client 1 is logged in and is a member of the Admin group via an access token. + */ + let GRAPHQL_CLIENT_1_ACCESS: GraphQLClient; + + /** + * Client 2 is logged in and is a member of the Devs group. + */ + let GRAPHQL_CLIENT_2: GraphQLClient; + + /** + * Client 3 is logged in and is a member of the Devs-Admin group via an access token. + */ + let GRAPHQL_CLIENT_3: GraphQLClient; + + // env info + const USERNAME1 = 'user1@test.com'; + const USERNAME2 = 'user2@test.com'; + const USERNAME3 = 'user3@test.com'; + const TMP_PASSWORD = 'Password123!'; + const REAL_PASSWORD = 'Password1234!'; + + const ADMIN_GROUP_NAME = 'Admin'; + const DEVS_GROUP_NAME = 'Devs'; + const DEVS_ADMIN_GROUP_NAME = 'Devs-Admin'; + const PARTICIPANT_GROUP_NAME = 'Participant'; + const WATCHER_GROUP_NAME = 'Watcher'; + + function outputValueSelector(key: string) { + return (outputs: Output[]) => { + const output = outputs.find((o: Output) => o.OutputKey === key); + return output ? output.OutputValue : null; + }; + } + beforeAll(async () => { + const validSchema = ` + type Post @model @auth(rules: [{ allow: owner }]) { + id: ID! + title: String! + createdAt: AWSDateTime + updatedAt: AWSDateTime + owner: String + } + type Salary + @model + @auth(rules: [{ allow: owner }, { allow: groups, groups: ["Admin"] }]) { + id: ID! + wage: Int + owner: String + } + type AdminNote + @model + @auth( + rules: [{ allow: groups, groups: ["Admin"], groupClaim: "cognito:groups" }] + ) { + id: ID! + content: String! + } + type ManyGroupProtected + @model + @auth(rules: [{ allow: groups, groupsField: "groups" }]) { + id: ID! + value: Int + groups: [String] + } + type SingleGroupProtected + @model + @auth(rules: [{ allow: groups, groupsField: "group" }]) { + id: ID! + value: Int + group: String + } + type PWProtected + @auth( + rules: [ + { + allow: groups + groups: ["Devs"] + } + { + allow: groups + groupsField: "participants" + operations: [read, update, delete] + } + { allow: groups, groupsField: "watchers", operations: [read] } + ] + ) + @model { + id: ID! + content: String! + participants: String + watchers: String + } + type AllThree + @auth( + rules: [ + { allow: owner, identityClaim: "username" } + { allow: owner, ownerField: "editors", identityClaim: "cognito:username" } + { allow: groups, groups: ["Admin", "Execs"] } + { allow: groups, groupsField: "groups" } + { allow: groups, groupsField: "alternativeGroup" } + ] + ) + @model { + id: ID! + owner: String + editors: [String] + groups: [String] + alternativeGroup: String + } + # The owner should always start with https://cognito-idp + type TestIdentity + @model + @auth(rules: [{ allow: owner, identityClaim: "iss" }]) { + id: ID! + title: String! + owner: String + } + type OwnerReadProtected + @model + @auth(rules: [{ allow: groups, groups: ["Admin"]},{ allow: owner, operations: [read] }]) { + id: ID! @primaryKey(sortKeyFields: ["sk"]) + sk: String! + content: String + owner: String + } + type OwnerCreateUpdateDeleteProtected + @model + @auth(rules: [{ allow: owner, operations: [create, update, delete] }]) { + id: ID! + content: String + owner: String + } + type Performance + @model + @auth( + rules: [ + { allow: groups, groups: ["Admin"] } + { allow: private, operations: [read] } + ] + ) { + id: ID + performer: String! + description: String! + time: AWSDateTime + stage: Stage @hasOne + } + type Stage + @model + @auth( + rules: [ + { allow: groups, groups: ["Admin"] } + { allow: private, operations: [read] } + ] + ) { + id: ID! + name: String! + }`; + try { + await awsS3Client.createBucket({ Bucket: BUCKET_NAME }).promise(); + } catch (e) { + throw Error(`Could not create bucket: ${e}`); + } + const authConfig: AppSyncAuthConfiguration = { + defaultAuthentication: { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + }, + additionalAuthenticationProviders: [], + }; + const transformer = new GraphQLTransform({ + authConfig, + transformers: [ + new ModelTransformer(), + new PrimaryKeyTransformer(), + new IndexTransformer(), + new HasOneTransformer(), + new AuthTransformer({ + authConfig, + addAwsIamAuthInOutputSchema: false, + }), + ], + }); + const userPoolResponse = await createUserPool(cognitoClient, `UserPool${STACK_NAME}`); + USER_POOL_ID = userPoolResponse.UserPool.Id; + const userPoolClientResponse = await createUserPoolClient(cognitoClient, USER_POOL_ID, `UserPool${STACK_NAME}`); + const userPoolClientId = userPoolClientResponse.UserPoolClient.ClientId; + try { + const out = transformer.transform(validSchema); + const finishedStack = await deploy( + customS3Client, + cf, + STACK_NAME, + out, + { AuthCognitoUserPoolId: USER_POOL_ID }, + LOCAL_FS_BUILD_DIR, + BUCKET_NAME, + S3_ROOT_DIR_KEY, + BUILD_TIMESTAMP, + ); + // Wait for any propagation to avoid random + // "The security token included in the request is invalid" errors + await new Promise(res => setTimeout(() => res(), 5000)); + + expect(finishedStack).toBeDefined(); + const getApiEndpoint = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIEndpointOutput); + const getApiKey = outputValueSelector(ResourceConstants.OUTPUTS.GraphQLAPIApiKeyOutput); + GRAPHQL_ENDPOINT = getApiEndpoint(finishedStack.Outputs); + + const apiKey = getApiKey(finishedStack.Outputs); + expect(apiKey).not.toBeTruthy(); + + // Verify we have all the details + expect(GRAPHQL_ENDPOINT).toBeTruthy(); + expect(USER_POOL_ID).toBeTruthy(); + expect(userPoolClientId).toBeTruthy(); + + // Configure Amplify, create users, and sign in + configureAmplify(USER_POOL_ID, userPoolClientId); + + await signupUser(USER_POOL_ID, USERNAME1, TMP_PASSWORD); + await signupUser(USER_POOL_ID, USERNAME2, TMP_PASSWORD); + await signupUser(USER_POOL_ID, USERNAME3, TMP_PASSWORD); + await createGroup(USER_POOL_ID, ADMIN_GROUP_NAME); + await createGroup(USER_POOL_ID, PARTICIPANT_GROUP_NAME); + await createGroup(USER_POOL_ID, WATCHER_GROUP_NAME); + await createGroup(USER_POOL_ID, DEVS_GROUP_NAME); + await createGroup(USER_POOL_ID, DEVS_ADMIN_GROUP_NAME); + await addUserToGroup(ADMIN_GROUP_NAME, USERNAME1, USER_POOL_ID); + await addUserToGroup(PARTICIPANT_GROUP_NAME, USERNAME1, USER_POOL_ID); + await addUserToGroup(WATCHER_GROUP_NAME, USERNAME1, USER_POOL_ID); + await addUserToGroup(DEVS_GROUP_NAME, USERNAME2, USER_POOL_ID); + await addUserToGroup(DEVS_ADMIN_GROUP_NAME, USERNAME3, USER_POOL_ID); + const authResAfterGroup: any = await authenticateUser(USERNAME1, TMP_PASSWORD, REAL_PASSWORD); + + const idToken = authResAfterGroup.getIdToken().getJwtToken(); + GRAPHQL_CLIENT_1 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken }); + + const accessToken = authResAfterGroup.getAccessToken().getJwtToken(); + GRAPHQL_CLIENT_1_ACCESS = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: accessToken }); + + const authRes2AfterGroup: any = await authenticateUser(USERNAME2, TMP_PASSWORD, REAL_PASSWORD); + const idToken2 = authRes2AfterGroup.getIdToken().getJwtToken(); + GRAPHQL_CLIENT_2 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken2 }); + + const authRes3AfterGroup: any = await authenticateUser(USERNAME3, TMP_PASSWORD, REAL_PASSWORD); + const idToken3 = authRes3AfterGroup.getIdToken().getJwtToken(); + GRAPHQL_CLIENT_3 = new GraphQLClient(GRAPHQL_ENDPOINT, { Authorization: idToken3 }); + } catch (e) { + console.error(`Could not setup transformer ${e}`); + expect(true).toBe(false); + } + }); + + afterAll(async () => { + await cleanupStackAfterTest(BUCKET_NAME, STACK_NAME, cf, { cognitoClient, userPoolId: USER_POOL_ID }); + }); + + /** + * Test queries below + */ + test('Test createPost mutation', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toEqual(USERNAME1); + + const response2 = await GRAPHQL_CLIENT_1_ACCESS.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response2.data.createPost.id).toBeDefined(); + expect(response2.data.createPost.title).toEqual('Hello, World!'); + expect(response2.data.createPost.createdAt).toBeDefined(); + expect(response2.data.createPost.updatedAt).toBeDefined(); + expect(response2.data.createPost.owner).toEqual(USERNAME1); + }); + + test('Test getPost query when authorized', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toEqual(USERNAME1); + const getResponse = await GRAPHQL_CLIENT_1.query( + `query { + getPost(id: "${response.data.createPost.id}") { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(getResponse.data.getPost.id).toBeDefined(); + expect(getResponse.data.getPost.title).toEqual('Hello, World!'); + expect(getResponse.data.getPost.createdAt).toBeDefined(); + expect(getResponse.data.getPost.updatedAt).toBeDefined(); + expect(getResponse.data.getPost.owner).toEqual(USERNAME1); + + const getResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( + `query { + getPost(id: "${response.data.createPost.id}") { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(getResponseAccess.data.getPost.id).toBeDefined(); + expect(getResponseAccess.data.getPost.title).toEqual('Hello, World!'); + expect(getResponseAccess.data.getPost.createdAt).toBeDefined(); + expect(getResponseAccess.data.getPost.updatedAt).toBeDefined(); + expect(getResponseAccess.data.getPost.owner).toEqual(USERNAME1); + }); + + test('Test getPost query when not authorized', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toBeDefined(); + const getResponse = await GRAPHQL_CLIENT_2.query( + `query { + getPost(id: "${response.data.createPost.id}") { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(getResponse.data.getPost).toEqual(null); + expect(getResponse.errors.length).toEqual(1); + expect((getResponse.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test('Test updatePost mutation when authorized', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toEqual(USERNAME1); + const updateResponse = await GRAPHQL_CLIENT_1.query( + `mutation { + updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(updateResponse.data.updatePost.id).toEqual(response.data.createPost.id); + expect(updateResponse.data.updatePost.title).toEqual('Bye, World!'); + expect(updateResponse.data.updatePost.updatedAt > response.data.createPost.updatedAt).toEqual(true); + + const updateResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( + `mutation { + updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(updateResponseAccess.data.updatePost.id).toEqual(response.data.createPost.id); + expect(updateResponseAccess.data.updatePost.title).toEqual('Bye, World!'); + expect(updateResponseAccess.data.updatePost.updatedAt > response.data.createPost.updatedAt).toEqual(true); + }); + + test('Test updatePost mutation when not authorized', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toBeDefined(); + const updateResponse = await GRAPHQL_CLIENT_2.query( + `mutation { + updatePost(input: { id: "${response.data.createPost.id}", title: "Bye, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(updateResponse.data.updatePost).toEqual(null); + expect(updateResponse.errors.length).toEqual(1); + expect((updateResponse.errors[0] as any).data).toBeNull(); + expect((updateResponse.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test('Test deletePost mutation when authorized', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toEqual(USERNAME1); + const deleteResponse = await GRAPHQL_CLIENT_1.query( + `mutation { + deletePost(input: { id: "${response.data.createPost.id}" }) { + id + } + }`, + {}, + ); + expect(deleteResponse.data.deletePost.id).toEqual(response.data.createPost.id); + + const responseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(responseAccess.data.createPost.id).toBeDefined(); + expect(responseAccess.data.createPost.title).toEqual('Hello, World!'); + expect(responseAccess.data.createPost.createdAt).toBeDefined(); + expect(responseAccess.data.createPost.updatedAt).toBeDefined(); + expect(responseAccess.data.createPost.owner).toEqual(USERNAME1); + const deleteResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( + `mutation { + deletePost(input: { id: "${responseAccess.data.createPost.id}" }) { + id + } + }`, + {}, + ); + expect(deleteResponseAccess.data.deletePost.id).toEqual(responseAccess.data.createPost.id); + }); + + test('Test deletePost mutation when not authorized', async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "Hello, World!" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(response.data.createPost.id).toBeDefined(); + expect(response.data.createPost.title).toEqual('Hello, World!'); + expect(response.data.createPost.createdAt).toBeDefined(); + expect(response.data.createPost.updatedAt).toBeDefined(); + expect(response.data.createPost.owner).toEqual(USERNAME1); + const deleteResponse = await GRAPHQL_CLIENT_2.query( + `mutation { + deletePost(input: { id: "${response.data.createPost.id}" }) { + id + } + }`, + {}, + ); + expect(deleteResponse.data.deletePost).toEqual(null); + expect(deleteResponse.errors.length).toEqual(1); + expect((deleteResponse.errors[0] as any).data).toBeNull(); + expect((deleteResponse.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test('Test listPosts query when authorized', async () => { + const firstPost = await GRAPHQL_CLIENT_1.query( + `mutation { + createPost(input: { title: "testing list" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + expect(firstPost.data.createPost.id).toBeDefined(); + expect(firstPost.data.createPost.title).toEqual('testing list'); + expect(firstPost.data.createPost.createdAt).toBeDefined(); + expect(firstPost.data.createPost.updatedAt).toBeDefined(); + expect(firstPost.data.createPost.owner).toEqual(USERNAME1); + await GRAPHQL_CLIENT_2.query( + `mutation { + createPost(input: { title: "testing list" }) { + id + title + createdAt + updatedAt + owner + } + }`, + {}, + ); + // There are two posts but only 1 created by me. + const listResponse = await GRAPHQL_CLIENT_1.query( + `query { + listPosts(filter: { title: { eq: "testing list" } }, limit: 25) { + items { + id + } + } + }`, + {}, + ); + expect(listResponse.data.listPosts.items.length).toEqual(1); + + const listResponseAccess = await GRAPHQL_CLIENT_1_ACCESS.query( + `query { + listPosts(filter: { title: { eq: "testing list" } }, limit: 25) { + items { + id + } + } + }`, + {}, + ); + expect(listResponseAccess.data.listPosts.items.length).toEqual(1); + }); + + /** + * Static Group Auth + */ + test(`Test createSalary w/ Admin group protection authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 10 }) { + id + wage + } + } + `, + {}, + ); + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(10); + }); + + test(`Test update my own salary without admin permission`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createSalary(input: { wage: 10 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.wage).toEqual(10); + const req2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateSalary(input: { id: "${req.data.createSalary.id}", wage: 14 }) { + id + wage + } + } + `, + {}, + ); + + expect(req2.data.updateSalary.wage).toEqual(14); + }); + + test(`Test updating someone else's salary as an admin`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createSalary(input: { wage: 11 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(11); + const req2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + updateSalary(input: { id: "${req.data.createSalary.id}", wage: 12 }) { + id + wage + } + } + `, + {}, + ); + + expect(req2.data.updateSalary.id).toEqual(req.data.createSalary.id); + expect(req2.data.updateSalary.wage).toEqual(12); + }); + + test(`Test updating someone else's salary when I am not admin.`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 13 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(13); + const req2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateSalary(input: { id: "${req.data.createSalary.id}", wage: 14 }) { + id + wage + } + } + `, + {}, + ); + expect(req2.data.updateSalary).toEqual(null); + expect(req2.errors.length).toEqual(1); + expect((req2.errors[0] as any).data).toBeNull(); + expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test deleteSalary w/ Admin group protection authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 15 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(15); + const req2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteSalary(input: { id: "${req.data.createSalary.id}" }) { + id + wage + } + } + `, + {}, + ); + + expect(req2.data.deleteSalary.id).toEqual(req.data.createSalary.id); + expect(req2.data.deleteSalary.wage).toEqual(15); + }); + + test(`Test deleteSalary w/ Admin group protection not authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 16 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(16); + const req2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + deleteSalary(input: { id: "${req.data.createSalary.id}" }) { + id + wage + } + } + `, + {}, + ); + expect(req2.data.deleteSalary).toEqual(null); + expect(req2.errors.length).toEqual(1); + expect((req2.errors[0] as any).data).toBeNull(); + expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test and Admin can get a salary created by any user`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createSalary(input: { wage: 15 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(15); + const req2 = await GRAPHQL_CLIENT_1.query( + ` + query { + getSalary(id: "${req.data.createSalary.id}") { + id + wage + } + } + `, + {}, + ); + expect(req2.data.getSalary.id).toEqual(req.data.createSalary.id); + expect(req2.data.getSalary.wage).toEqual(15); + }); + + test(`Test owner can create and get a salary when not admin`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createSalary(input: { wage: 15 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(15); + const req2 = await GRAPHQL_CLIENT_2.query( + ` + query { + getSalary(id: "${req.data.createSalary.id}") { + id + wage + } + } + `, + {}, + ); + expect(req2.data.getSalary.id).toEqual(req.data.createSalary.id); + expect(req2.data.getSalary.wage).toEqual(15); + }); + + test(`Test getSalary w/ Admin group protection not authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 16 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(16); + const req2 = await GRAPHQL_CLIENT_2.query( + ` + query { + getSalary(id: "${req.data.createSalary.id}") { + id + wage + } + } + `, + {}, + ); + expect(req2.data.getSalary).toEqual(null); + expect(req2.errors.length).toEqual(1); + expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test listSalaries w/ Admin group protection authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 101 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(101); + const req2 = await GRAPHQL_CLIENT_1.query( + ` + query { + listSalaries(filter: { wage: { eq: 101 }}) { + items { + id + wage + } + } + } + `, + {}, + ); + expect(req2.data.listSalaries.items.length).toEqual(1); + expect(req2.data.listSalaries.items[0].id).toEqual(req.data.createSalary.id); + expect(req2.data.listSalaries.items[0].wage).toEqual(101); + }); + + test(`Test listSalaries w/ Admin group protection not authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSalary(input: { wage: 102 }) { + id + wage + } + } + `, + {}, + ); + + expect(req.data.createSalary.id).toBeDefined(); + expect(req.data.createSalary.wage).toEqual(102); + const req2 = await GRAPHQL_CLIENT_2.query( + ` + query { + listSalaries(filter: { wage: { eq: 102 }}) { + items { + id + wage + } + } + } + `, + {}, + ); + expect(req2.data.listSalaries.items).toEqual([]); + }); + + /** + * Dynamic Group Auth + */ + test(`Test createManyGroupProtected w/ dynamic group protection authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createManyGroupProtected(input: { value: 10, groups: ["Admin"] }) { + id + value + groups + } + } + `, + {}, + ); + + expect(req.data.createManyGroupProtected.id).toBeDefined(); + expect(req.data.createManyGroupProtected.value).toEqual(10); + expect(req.data.createManyGroupProtected.groups).toEqual(['Admin']); + }); + + test(`Test createManyGroupProtected w/ dynamic group protection when not authorized`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createManyGroupProtected(input: { value: 10, groups: ["Admin"] }) { + id + value + groups + } + } + `, + {}, + ); + + expect(req.data.createManyGroupProtected).toEqual(null); + expect(req.errors.length).toEqual(1); + expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test updateSingleGroupProtected when user is not authorized but has a group that is a substring of the allowed group`, async () => { + const req = await GRAPHQL_CLIENT_3.query( + `mutation { + createSingleGroupProtected(input: { value: 11, group: "Devs-Admin" }) { + id + value + group + } + } + `, + {}, + ); + + const req2 = await GRAPHQL_CLIENT_2.query( + `mutation { + updateSingleGroupProtected(input: {id: "${req.data.createSingleGroupProtected.id}", value: 5 }) { + id + value + group + } + } + `, + {}, + ); + + const req3 = await GRAPHQL_CLIENT_3.query( + `query { + getSingleGroupProtected(id: "${req.data.createSingleGroupProtected.id}") { + id + value + group + } + } + `, + {}, + ); + + expect(req.data.createSingleGroupProtected.value).toEqual(11); + expect(req.data.createSingleGroupProtected.value).toEqual(req3.data.getSingleGroupProtected.value); + expect((req2.errors[0] as any).data).toBeNull(); + expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test createSingleGroupProtected w/ dynamic group protection authorized`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createSingleGroupProtected(input: { value: 10, group: "Admin" }) { + id + value + group + } + } + `, + {}, + ); + + expect(req.data.createSingleGroupProtected.id).toBeDefined(); + expect(req.data.createSingleGroupProtected.value).toEqual(10); + expect(req.data.createSingleGroupProtected.group).toEqual('Admin'); + }); + + test(`Test createSingleGroupProtected w/ dynamic group protection when not authorized`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createSingleGroupProtected(input: { value: 10, group: "Admin" }) { + id + value + group + } + } + `, + {}, + ); + + expect(req.data.createSingleGroupProtected).toEqual(null); + expect(req.errors.length).toEqual(1); + expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test listPWProtecteds when the user is authorized.`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createPWProtected(input: { content: "Foobie", participants: "${PARTICIPANT_GROUP_NAME}", watchers: "${WATCHER_GROUP_NAME}" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + + expect(req.data.createPWProtected).toBeTruthy(); + + const uReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + updatePWProtected(input: { id: "${req.data.createPWProtected.id}", content: "Foobie2" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + expect(uReq.data.updatePWProtected).toBeTruthy(); + + const req2 = await GRAPHQL_CLIENT_1.query( + ` + query { + listPWProtecteds { + items { + id + content + participants + watchers + } + nextToken + } + } + `, + {}, + ); + expect(req2.data.listPWProtecteds.items.length).toEqual(1); + expect(req2.data.listPWProtecteds.items[0].id).toEqual(req.data.createPWProtected.id); + expect(req2.data.listPWProtecteds.items[0].content).toEqual('Foobie2'); + + const req3 = await GRAPHQL_CLIENT_1.query( + ` + query { + getPWProtected(id: "${req.data.createPWProtected.id}") { + id + content + participants + watchers + } + } + `, + {}, + ); + + expect(req3.data.getPWProtected).toBeTruthy(); + + const dReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deletePWProtected(input: { id: "${req.data.createPWProtected.id}" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + expect(dReq.data.deletePWProtected).toBeTruthy(); + }); + + test(`Test listPWProtecteds when groups is null in dynamodb.`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + `mutation { + createPWProtected(input: { content: "Foobie" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + + expect(req.data.createPWProtected).toBeTruthy(); + + const req2 = await GRAPHQL_CLIENT_1.query( + ` + query { + listPWProtecteds { + items { + id + content + participants + watchers + } + nextToken + } + } + `, + {}, + ); + expect(req2.data.listPWProtecteds.items.length).toEqual(0); + + const req3 = await GRAPHQL_CLIENT_1.query( + ` + query { + getPWProtected(id: "${req.data.createPWProtected.id}") { + id + content + participants + watchers + } + } + `, + {}, + ); + + expect(req3.data.getPWProtected).toEqual(null); + expect(req3.errors.length).toEqual(1); + expect((req3.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + test(`Test Protecteds when the user is not authorized.`, async () => { + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createPWProtected(input: { content: "Barbie", participants: "${PARTICIPANT_GROUP_NAME}", watchers: "${WATCHER_GROUP_NAME}" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + + expect(req.data.createPWProtected).toBeTruthy(); + + const req2 = await GRAPHQL_CLIENT_3.query( + ` + query { + listPWProtecteds { + items { + id + content + participants + watchers + } + nextToken + } + } + `, + {}, + ); + + expect(req2.data.listPWProtecteds.items.length).toEqual(0); + expect(req2.data.listPWProtecteds.nextToken).toBeNull(); + + const uReq = await GRAPHQL_CLIENT_3.query( + ` + mutation { + updatePWProtected(input: { id: "${req.data.createPWProtected.id}", content: "Foobie2" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + expect(uReq.data.updatePWProtected).toBeNull(); + + const req3 = await GRAPHQL_CLIENT_3.query( + ` + query { + getPWProtected(id: "${req.data.createPWProtected.id}") { + id + content + participants + watchers + } + } + `, + {}, + ); + + expect(req3.data.getPWProtected).toBeNull(); + + const dReq = await GRAPHQL_CLIENT_3.query( + ` + mutation { + deletePWProtected(input: { id: "${req.data.createPWProtected.id}" }) { + id + content + participants + watchers + } + } + `, + {}, + ); + expect(dReq.data.deletePWProtected).toBeNull(); + + // The record should still exist after delete. + const getReq = await GRAPHQL_CLIENT_1.query( + ` + query { + getPWProtected(id: "${req.data.createPWProtected.id}") { + id + content + participants + watchers + } + } + `, + {}, + ); + expect(getReq.data.getPWProtected).toBeTruthy(); + }); + + test(`Test creating, updating, and deleting an admin note as an admin`, async () => { + const req = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAdminNote(input: { content: "Hello" }) { + id + content + } + } + `, + {}, + ); + + expect(req.data.createAdminNote.id).toBeDefined(); + expect(req.data.createAdminNote.content).toEqual('Hello'); + const req2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + updateAdminNote(input: { id: "${req.data.createAdminNote.id}", content: "Hello 2" }) { + id + content + } + } + `, + {}, + ); + + expect(req2.data.updateAdminNote.id).toEqual(req.data.createAdminNote.id); + expect(req2.data.updateAdminNote.content).toEqual('Hello 2'); + const req3 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAdminNote(input: { id: "${req.data.createAdminNote.id}" }) { + id + content + } + } + `, + {}, + ); + + expect(req3.data.deleteAdminNote.id).toEqual(req.data.createAdminNote.id); + expect(req3.data.deleteAdminNote.content).toEqual('Hello 2'); + }); + + test(`Test creating, updating, and deleting an admin note as a non admin`, async () => { + const adminReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAdminNote(input: { content: "Hello" }) { + id + content + } + } + `, + {}, + ); + expect(adminReq.data.createAdminNote.id).toBeDefined(); + expect(adminReq.data.createAdminNote.content).toEqual('Hello'); + + const req = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAdminNote(input: { content: "Hello" }) { + id + content + } + } + `, + {}, + ); + + expect(req.errors.length).toEqual(1); + expect((req.errors[0] as any).errorType).toEqual('Unauthorized'); + + const req2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateAdminNote(input: { id: "${adminReq.data.createAdminNote.id}", content: "Hello 2" }) { + id + content + } + } + `, + {}, + ); + + expect(req2.errors.length).toEqual(1); + expect((req2.errors[0] as any).errorType).toEqual('Unauthorized'); + + const req3 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + deleteAdminNote(input: { id: "${adminReq.data.createAdminNote.id}" }) { + id + content + } + } + `, + {}, + ); + + expect(req3.errors.length).toEqual(1); + expect((req3.errors[0] as any).errorType).toEqual('Unauthorized'); + }); + + /** + * Get Query Tests + */ + + test(`Test getAllThree as admin.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + + const fetchOwnedBy2AsAdmin = await GRAPHQL_CLIENT_1.query( + ` + query { + getAllThree(id: "${ownedBy2.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedBy2AsAdmin.data.getAllThree).toBeTruthy(); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test getAllThree as owner.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + + const fetchOwnedBy2AsOwner = await GRAPHQL_CLIENT_2.query( + ` + query { + getAllThree(id: "${ownedBy2.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedBy2AsOwner.data.getAllThree).toBeTruthy(); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test getAllThree as one of a set of editors.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + editors: ["user2@test.com"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + + const fetchOwnedBy2AsEditor = await GRAPHQL_CLIENT_2.query( + ` + query { + getAllThree(id: "${ownedBy2.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedBy2AsEditor.data.getAllThree).toBeTruthy(); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test getAllThree as a member of a dynamic group.`, async () => { + const ownedByAdmins = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + groups: ["Devs"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdmins.data.createAllThree).toBeTruthy(); + + const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( + ` + query { + getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsAdmin.data.getAllThree).toBeTruthy(); + + const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( + ` + query { + getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsNonAdmin.errors.length).toEqual(1); + expect((fetchOwnedByAdminsAsNonAdmin.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); + }); + + test(`Test getAllThree as a member of the alternative group.`, async () => { + const ownedByAdmins = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdmins.data.createAllThree).toBeTruthy(); + + const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( + ` + query { + getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsAdmin.data.getAllThree).toBeTruthy(); + + const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( + ` + query { + getAllThree(id: "${ownedByAdmins.data.createAllThree.id}") { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsNonAdmin.errors.length).toEqual(1); + expect((fetchOwnedByAdminsAsNonAdmin.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); + }); + + /** + * List Query Tests + */ + + test(`Test listAllThrees as admin.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + + const fetchOwnedBy2AsAdmin = await GRAPHQL_CLIENT_1.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedBy2AsAdmin.data.listAllThrees.items).toHaveLength(1); + expect(fetchOwnedBy2AsAdmin.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test listAllThrees as owner.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + + const fetchOwnedBy2AsOwner = await GRAPHQL_CLIENT_2.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedBy2AsOwner.data.listAllThrees.items).toHaveLength(1); + expect(fetchOwnedBy2AsOwner.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test listAllThrees as one of a set of editors.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + editors: ["user2@test.com"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + + const fetchOwnedBy2AsEditor = await GRAPHQL_CLIENT_2.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedBy2AsEditor.data.listAllThrees.items).toHaveLength(1); + expect(fetchOwnedBy2AsEditor.data.listAllThrees.items[0].id).toEqual(ownedBy2.data.createAllThree.id); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test listAllThrees as a member of a dynamic group.`, async () => { + const ownedByAdmins = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + groups: ["Devs"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdmins.data.createAllThree).toBeTruthy(); + + const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items).toHaveLength(1); + expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items[0].id).toEqual(ownedByAdmins.data.createAllThree.id); + + const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsNonAdmin.data.listAllThrees.items).toHaveLength(0); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); + }); + + test(`Test getAllThree as a member of the alternative group.`, async () => { + const ownedByAdmins = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdmins.data.createAllThree).toBeTruthy(); + + const fetchOwnedByAdminsAsAdmin = await GRAPHQL_CLIENT_2.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items).toHaveLength(1); + expect(fetchOwnedByAdminsAsAdmin.data.listAllThrees.items[0].id).toEqual(ownedByAdmins.data.createAllThree.id); + + const fetchOwnedByAdminsAsNonAdmin = await GRAPHQL_CLIENT_3.query( + ` + query { + listAllThrees { + items { + id + owner + editors + groups + alternativeGroup + } + } + } + `, + {}, + ); + expect(fetchOwnedByAdminsAsNonAdmin.data.listAllThrees.items).toHaveLength(0); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); + }); + + /** + * Create Mutation Tests + */ + + test(`Test createAllThree as admin.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + // set by input + expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); + // not auto filled as the admin condition was met + expect(ownedBy2.data.createAllThree.editors).toBeNull(); + expect(ownedBy2.data.createAllThree.groups).toBeNull(); + expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedBy2NoEditors = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com", + editors: [] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2NoEditors.data.createAllThree).toBeTruthy(); + // set by input + expect(ownedBy2NoEditors.data.createAllThree.owner).toEqual('user2@test.com'); + // set by input + expect(ownedBy2NoEditors.data.createAllThree.editors).toHaveLength(0); + expect(ownedBy2NoEditors.data.createAllThree.groups).toBeNull(); + expect(ownedBy2NoEditors.data.createAllThree.alternativeGroup).toBeNull(); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + + const deleteReq2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2NoEditors.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedBy2NoEditors.data.createAllThree.id); + }); + + test(`Test createAllThree as owner.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com", + editors: [] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); + expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); + expect(ownedBy2.data.createAllThree.groups).toBeNull(); + expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedBy1 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: "user1@test.com", + editors: [] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy1.errors.length).toEqual(1); + expect((ownedBy1.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test createAllThree as one of a set of editors.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: ["user2@test.com"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + expect(ownedBy2.data.createAllThree.owner).toBeNull(); + expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user2@test.com'); + expect(ownedBy2.data.createAllThree.groups).toBeNull(); + expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedBy2WithDefaultOwner = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + editors: ["user2@test.com"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2WithDefaultOwner.data.createAllThree).toBeTruthy(); + expect(ownedBy2WithDefaultOwner.data.createAllThree.owner).toEqual('user2@test.com'); + expect(ownedBy2WithDefaultOwner.data.createAllThree.editors[0]).toEqual('user2@test.com'); + expect(ownedBy2WithDefaultOwner.data.createAllThree.groups).toBeNull(); + expect(ownedBy2WithDefaultOwner.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedByEditorsUnauthed = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: ["user1@test.com"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByEditorsUnauthed.errors.length).toEqual(1); + expect((ownedByEditorsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + + const deleteReq2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2WithDefaultOwner.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedBy2WithDefaultOwner.data.createAllThree.id); + }); + + test(`Test createAllThree as a member of a dynamic group.`, async () => { + const ownedByDevs = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + groups: ["Devs"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByDevs.data.createAllThree).toBeTruthy(); + expect(ownedByDevs.data.createAllThree.owner).toBeNull(); + expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); + expect(ownedByDevs.data.createAllThree.groups[0]).toEqual('Devs'); + expect(ownedByDevs.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + groups: ["Devs"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdminsUnauthed.errors.length).toEqual(1); + expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); + }); + + test(`Test createAllThree as a member of the alternative group.`, async () => { + const ownedByAdmins = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdmins.data.createAllThree).toBeTruthy(); + expect(ownedByAdmins.data.createAllThree.owner).toBeNull(); + expect(ownedByAdmins.data.createAllThree.editors).toHaveLength(0); + expect(ownedByAdmins.data.createAllThree.alternativeGroup).toEqual('Devs'); + + const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + alternativeGroup: "Admin" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdminsUnauthed.errors.length).toEqual(1); + expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByAdmins.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByAdmins.data.createAllThree.id); + }); + + /** + * Update Mutation Tests + */ + + test(`Test updateAllThree and deleteAllThree as admin.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + editors: [] + owner: "user2@test.com" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + // set by input + expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); + // auto filled as logged in user. + expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); + expect(ownedBy2.data.createAllThree.groups).toBeNull(); + expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedByTwoUpdate = await GRAPHQL_CLIENT_1.query( + ` + mutation { + updateAllThree(input: { + id: "${ownedBy2.data.createAllThree.id}", + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByTwoUpdate.data.updateAllThree).toBeTruthy(); + // set by input + expect(ownedByTwoUpdate.data.updateAllThree.owner).toEqual('user2@test.com'); + // set by input + expect(ownedByTwoUpdate.data.updateAllThree.editors).toHaveLength(0); + expect(ownedByTwoUpdate.data.updateAllThree.groups).toBeNull(); + expect(ownedByTwoUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test updateAllThree and deleteAllThree as owner.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: "user2@test.com", + editors: [] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + expect(ownedBy2.data.createAllThree.owner).toEqual('user2@test.com'); + expect(ownedBy2.data.createAllThree.editors).toHaveLength(0); + expect(ownedBy2.data.createAllThree.groups).toBeNull(); + expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedBy2Update = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateAllThree(input: { + id: "${ownedBy2.data.createAllThree.id}", + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2Update.data.updateAllThree).toBeTruthy(); + // set by input + expect(ownedBy2Update.data.updateAllThree.owner).toEqual('user2@test.com'); + // set by input + expect(ownedBy2Update.data.updateAllThree.editors).toHaveLength(0); + expect(ownedBy2Update.data.updateAllThree.groups).toBeNull(); + expect(ownedBy2Update.data.updateAllThree.alternativeGroup).toEqual('Devs'); + + const deleteReq = await GRAPHQL_CLIENT_2.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test updateAllThree and deleteAllThree as one of a set of editors.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: ["user2@test.com"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedBy2.data.createAllThree).toBeTruthy(); + expect(ownedBy2.data.createAllThree.owner).toBeNull(); + expect(ownedBy2.data.createAllThree.editors[0]).toEqual('user2@test.com'); + expect(ownedBy2.data.createAllThree.groups).toBeNull(); + expect(ownedBy2.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedByUpdate = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateAllThree(input: { + id: "${ownedBy2.data.createAllThree.id}", + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); + // set by input + expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); + // set by input + expect(ownedByUpdate.data.updateAllThree.editors[0]).toEqual('user2@test.com'); + expect(ownedByUpdate.data.updateAllThree.groups).toBeNull(); + expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); + + const deleteReq = await GRAPHQL_CLIENT_2.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedBy2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedBy2.data.createAllThree.id); + }); + + test(`Test updateAllThree and deleteAllThree as a member of a dynamic group.`, async () => { + const ownedByDevs = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + groups: ["Devs"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByDevs.data.createAllThree).toBeTruthy(); + expect(ownedByDevs.data.createAllThree.owner).toBeNull(); + expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); + expect(ownedByDevs.data.createAllThree.groups[0]).toEqual('Devs'); + expect(ownedByDevs.data.createAllThree.alternativeGroup).toBeNull(); + + const ownedByUpdate = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateAllThree(input: { + id: "${ownedByDevs.data.createAllThree.id}", + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); + // set by input + expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); + // set by input + expect(ownedByUpdate.data.updateAllThree.editors).toHaveLength(0); + expect(ownedByUpdate.data.updateAllThree.groups[0]).toEqual('Devs'); + expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Devs'); + + const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_3.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + groups: ["Devs"] + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdminsUnauthed.errors.length).toEqual(1); + expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); + }); + + test(`Test updateAllThree and deleteAllThree as a member of the alternative group.`, async () => { + const ownedByDevs = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByDevs.data.createAllThree).toBeTruthy(); + expect(ownedByDevs.data.createAllThree.owner).toBeNull(); + expect(ownedByDevs.data.createAllThree.editors).toHaveLength(0); + expect(ownedByDevs.data.createAllThree.alternativeGroup).toEqual('Devs'); + + const ownedByUpdate = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateAllThree(input: { + id: "${ownedByDevs.data.createAllThree.id}", + alternativeGroup: "Admin" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByUpdate.data.updateAllThree).toBeTruthy(); + // set by input + expect(ownedByUpdate.data.updateAllThree.owner).toBeNull(); + // set by input + expect(ownedByUpdate.data.updateAllThree.editors).toHaveLength(0); + expect(ownedByUpdate.data.updateAllThree.groups).toBeNull(); + expect(ownedByUpdate.data.updateAllThree.alternativeGroup).toEqual('Admin'); + + const ownedByAdminsUnauthed = await GRAPHQL_CLIENT_2.query( + ` + mutation { + updateAllThree(input: { + id: "${ownedByDevs.data.createAllThree.id}", + alternativeGroup: "Dev" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByAdminsUnauthed.errors.length).toEqual(1); + expect((ownedByAdminsUnauthed.errors[0] as any).data).toBeNull(); + expect((ownedByAdminsUnauthed.errors[0] as any).errorType).toEqual('Unauthorized'); + + const ownedByDevs2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createAllThree(input: { + owner: null, + editors: [], + alternativeGroup: "Devs" + }) { + id + owner + editors + groups + alternativeGroup + } + } + `, + {}, + ); + expect(ownedByDevs2.data.createAllThree).toBeTruthy(); + expect(ownedByDevs2.data.createAllThree.owner).toBeNull(); + expect(ownedByDevs2.data.createAllThree.editors).toHaveLength(0); + expect(ownedByDevs2.data.createAllThree.alternativeGroup).toEqual('Devs'); + + const deleteReq2 = await GRAPHQL_CLIENT_2.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByDevs2.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq2.data.deleteAllThree.id).toEqual(ownedByDevs2.data.createAllThree.id); + + const deleteReq = await GRAPHQL_CLIENT_1.query( + ` + mutation { + deleteAllThree(input: { id: "${ownedByDevs.data.createAllThree.id}" }) { + id + } + } + `, + {}, + ); + expect(deleteReq.data.deleteAllThree.id).toEqual(ownedByDevs.data.createAllThree.id); + }); + + test(`Test createTestIdentity as admin.`, async () => { + const ownedBy2 = await GRAPHQL_CLIENT_1.query( + ` + mutation { + createTestIdentity(input: { + title: "Test title" + }) { + id + title + owner + } + } + `, + {}, + ); + expect(ownedBy2.data.createTestIdentity).toBeTruthy(); + expect(ownedBy2.data.createTestIdentity.title).toEqual('Test title'); + expect(ownedBy2.data.createTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); + + // user 2 should be able to update because they share the same issuer. + const update = await GRAPHQL_CLIENT_3.query( + ` + mutation { + updateTestIdentity(input: { + id: "${ownedBy2.data.createTestIdentity.id}", + title: "Test title update" + }) { + id + title + owner + } + } + `, + {}, + ); + expect(update.data.updateTestIdentity).toBeTruthy(); + expect(update.data.updateTestIdentity.title).toEqual('Test title update'); + expect(update.data.updateTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); + + // user 2 should be able to get because they share the same issuer. + const getReq = await GRAPHQL_CLIENT_3.query( + ` + query { + getTestIdentity(id: "${ownedBy2.data.createTestIdentity.id}") { + id + title + owner + } + } + `, + {}, + ); + expect(getReq.data.getTestIdentity).toBeTruthy(); + expect(getReq.data.getTestIdentity.title).toEqual('Test title update'); + expect(getReq.data.getTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); + + const listResponse = await GRAPHQL_CLIENT_3.query( + `query { + listTestIdentities(filter: { title: { eq: "Test title update" } }, limit: 100) { + items { + id + title + owner + } + } + }`, + {}, + ); + const relevantPost = listResponse.data.listTestIdentities.items.find(p => p.id === getReq.data.getTestIdentity.id); + expect(relevantPost).toBeTruthy(); + expect(relevantPost.title).toEqual('Test title update'); + expect(relevantPost.owner.slice(0, 19)).toEqual('https://cognito-idp'); + + // user 2 should be able to delete because they share the same issuer. + const delReq = await GRAPHQL_CLIENT_3.query( + ` + mutation { + deleteTestIdentity(input: { + id: "${ownedBy2.data.createTestIdentity.id}" + }) { + id + title + owner + } + } + `, + {}, + ); + expect(delReq.data.deleteTestIdentity).toBeTruthy(); + expect(delReq.data.deleteTestIdentity.title).toEqual('Test title update'); + expect(delReq.data.deleteTestIdentity.owner.slice(0, 19)).toEqual('https://cognito-idp'); + }); + + /** + * Test 'operations' argument + */ + test("Test get and list with 'read' operation set", async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createNoOwner: createOwnerReadProtected(input: { id: "1", sk: "1", content: "Hello, World! - No Owner" }) { + id + content + owner + } + createOwnerReadProtected(input: { id: "1", sk: "2", content: "Hello, World!", owner: "${USERNAME2}" }) { + id + content + owner + } + createNoOwner2: createOwnerReadProtected(input: { id: "1", sk: "3", content: "Hello, World! - No Owner 2" }) { + id + content + owner + } + }`, + {}, + ); + + expect(response.data.createOwnerReadProtected.id).toBeDefined(); + expect(response.data.createOwnerReadProtected.content).toEqual('Hello, World!'); + expect(response.data.createOwnerReadProtected.owner).toEqual(USERNAME2); + + const response2 = await GRAPHQL_CLIENT_3.query( + `query { + getOwnerReadProtected(id: "${response.data.createOwnerReadProtected.id}", sk:"2") { + id content owner + } + }`, + {}, + ); + expect(response2.data.getOwnerReadProtected).toBeNull(); + expect(response2.errors).toHaveLength(1); + + const response3 = await GRAPHQL_CLIENT_2.query( + `query { + getOwnerReadProtected(id: "${response.data.createOwnerReadProtected.id}", sk:"2") { + id content owner + } + }`, + {}, + ); + expect(response3.data.getOwnerReadProtected.id).toBeDefined(); + expect(response3.data.getOwnerReadProtected.content).toEqual('Hello, World!'); + expect(response3.data.getOwnerReadProtected.owner).toEqual(USERNAME2); + + const response4 = await GRAPHQL_CLIENT_2.query( + `query { + listOwnerReadProtecteds(id: "1") { + items { + id content owner + } + } + }`, + {}, + ); + expect(response4.data.listOwnerReadProtecteds.items.length).toEqual(1); + + const response5 = await GRAPHQL_CLIENT_3.query( + `query { + listOwnerReadProtecteds { + items { + id content owner + } + } + }`, + {}, + ); + expect(response5.data.listOwnerReadProtecteds.items).toHaveLength(0); + }); + + test("Test createOwnerCreateUpdateDeleteProtected with 'create' operation set", async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { + id + content + owner + } + }`, + {}, + ); + expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); + expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); + expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); + + const response2 = await GRAPHQL_CLIENT_1.query( + `mutation { + createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME2}" }) { + id + content + owner + } + }`, + {}, + ); + expect(response2.data.createOwnerCreateUpdateDeleteProtected).toBeNull(); + expect(response2.errors).toHaveLength(1); + }); + + test("Test updateOwnerCreateUpdateDeleteProtected with 'update' operation set", async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { + id + content + owner + } + }`, + {}, + ); + expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); + expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); + expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); + + const response2 = await GRAPHQL_CLIENT_2.query( + `mutation { + updateOwnerCreateUpdateDeleteProtected( + input: { + id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}", + content: "Bye, World!" + } + ) { + id + content + owner + } + }`, + {}, + ); + expect(response2.data.updateOwnerCreateUpdateDeleteProtected).toBeNull(); + expect(response2.errors).toHaveLength(1); + + const response3 = await GRAPHQL_CLIENT_1.query( + `mutation { + updateOwnerCreateUpdateDeleteProtected( + input: { + id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}", + content: "Bye, World!" + } + ) { + id + content + owner + } + }`, + {}, + ); + expect(response3.data.updateOwnerCreateUpdateDeleteProtected.id).toBeDefined(); + expect(response3.data.updateOwnerCreateUpdateDeleteProtected.content).toEqual('Bye, World!'); + expect(response3.data.updateOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); + }); + + test("Test deleteOwnerCreateUpdateDeleteProtected with 'update' operation set", async () => { + const response = await GRAPHQL_CLIENT_1.query( + `mutation { + createOwnerCreateUpdateDeleteProtected(input: { content: "Hello, World!", owner: "${USERNAME1}" }) { + id + content + owner + } + }`, + {}, + ); + expect(response.data.createOwnerCreateUpdateDeleteProtected.id).toBeDefined(); + expect(response.data.createOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); + expect(response.data.createOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); + + const response2 = await GRAPHQL_CLIENT_2.query( + `mutation { + deleteOwnerCreateUpdateDeleteProtected( + input: { + id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}" + } + ) { + id + content + owner + } + }`, + {}, + ); + expect(response2.data.deleteOwnerCreateUpdateDeleteProtected).toBeNull(); + expect(response2.errors).toHaveLength(1); + + const response3 = await GRAPHQL_CLIENT_1.query( + `mutation { + deleteOwnerCreateUpdateDeleteProtected( + input: { + id: "${response.data.createOwnerCreateUpdateDeleteProtected.id}" + } + ) { + id + content + owner + } + }`, + {}, + ); + expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.id).toBeDefined(); + expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.content).toEqual('Hello, World!'); + expect(response3.data.deleteOwnerCreateUpdateDeleteProtected.owner).toEqual(USERNAME1); + }); + + test('Test allow private combined with groups as Admin and non-admin users', async () => { + const create = `mutation { + p1: createPerformance(input: { + id: "P1" + performer: "Perf #1" + description: "Description" + time: "2019-11-11T00:00:00Z" + performanceStageId: "S1" + }) { + id + } + + p2: createPerformance(input: { + id: "P2" + performer: "Perf #2" + description: "Description" + time: "2019-11-11T00:00:00Z" + performanceStageId: "S1" + }) { + id + } + + s1: createStage(input: { + id: "S1" + name: "Stage #1" + }) { + id + } + } + `; + + // Create as non-admin user, should fail + const response1 = await GRAPHQL_CLIENT_3.query(create, {}); + + expect(response1.data.p1).toBeNull(); + expect(response1.data.p2).toBeNull(); + expect(response1.data.s1).toBeNull(); + expect(response1.errors.length).toEqual(3); + expect((response1.errors[0] as any).errorType).toEqual('Unauthorized'); + expect((response1.errors[1] as any).errorType).toEqual('Unauthorized'); + expect((response1.errors[2] as any).errorType).toEqual('Unauthorized'); + + // Create as Admin, should succeed + const response2 = await GRAPHQL_CLIENT_1.query(create, {}); + + expect(response2.data.p1.id).toEqual('P1'); + expect(response2.data.p2.id).toEqual('P2'); + expect(response2.data.s1.id).toEqual('S1'); + + const update = `mutation { + updatePerformance(input: { + id: "P1" + performer: "Best Perf #1" + }) { + id + performer + } + } + `; + + // Update as non-admin user, should fail + const response3 = await GRAPHQL_CLIENT_3.query(update, {}); + + expect(response3.data.updatePerformance).toBeNull(); + expect(response3.errors.length).toEqual(1); + expect((response3.errors[0] as any).errorType).toEqual('Unauthorized'); + + // Update as Admin, should succeed + const response4 = await GRAPHQL_CLIENT_1.query(update, {}); + + expect(response4.data.updatePerformance.id).toEqual('P1'); + expect(response4.data.updatePerformance.performer).toEqual('Best Perf #1'); + + // List as non-admin and Admin user as well, should succeed + const list = `query List { + listPerformances { + items { + id + performer + description + time + stage { + name + } + } + } + } + `; + + const response5 = await GRAPHQL_CLIENT_3.query(list, {}); + + expect(response5.data.listPerformances).toBeDefined(); + expect(response5.data.listPerformances.items).toBeDefined(); + expect(response5.data.listPerformances.items.length).toEqual(2); + expect(response5.data.listPerformances.items[0].id).toEqual('P2'); + expect(response5.data.listPerformances.items[0].performer).toEqual('Perf #2'); + expect(response5.data.listPerformances.items[0].stage).toBeDefined(); + expect(response5.data.listPerformances.items[0].stage.name).toEqual('Stage #1'); + expect(response5.data.listPerformances.items[1].id).toEqual('P1'); + expect(response5.data.listPerformances.items[1].performer).toEqual('Best Perf #1'); + expect(response5.data.listPerformances.items[1].stage).toBeDefined(); + expect(response5.data.listPerformances.items[1].stage.name).toEqual('Stage #1'); + + const response6 = await GRAPHQL_CLIENT_1.query(list, {}); + + expect(response6.data.listPerformances).toBeDefined(); + expect(response6.data.listPerformances.items).toBeDefined(); + expect(response6.data.listPerformances.items.length).toEqual(2); + expect(response6.data.listPerformances.items[0].id).toEqual('P2'); + expect(response6.data.listPerformances.items[0].performer).toEqual('Perf #2'); + expect(response6.data.listPerformances.items[0].stage).toBeDefined(); + expect(response6.data.listPerformances.items[0].stage.name).toEqual('Stage #1'); + expect(response6.data.listPerformances.items[1].id).toEqual('P1'); + expect(response6.data.listPerformances.items[1].performer).toEqual('Best Perf #1'); + expect(response6.data.listPerformances.items[1].stage.name).toEqual('Stage #1'); + expect(response6.data.listPerformances.items[1].stage).toBeDefined(); + + // Get as non-admin and Admin user as well, should succeed + const get = `query Get { + getPerformance(id: "P1") { + id + performer + description + time + stage { + name + } + } + } + `; + + const response7 = await GRAPHQL_CLIENT_3.query(get, {}); + + expect(response7.data.getPerformance).toBeDefined(); + expect(response7.data.getPerformance.id).toEqual('P1'); + expect(response7.data.getPerformance.performer).toEqual('Best Perf #1'); + expect(response7.data.getPerformance.stage).toBeDefined(); + expect(response7.data.getPerformance.stage.name).toEqual('Stage #1'); + + const response8 = await GRAPHQL_CLIENT_1.query(get, {}); + + expect(response8.data.getPerformance).toBeDefined(); + expect(response8.data.getPerformance.id).toEqual('P1'); + expect(response8.data.getPerformance.performer).toEqual('Best Perf #1'); + expect(response8.data.getPerformance.stage).toBeDefined(); + expect(response8.data.getPerformance.stage.name).toEqual('Stage #1'); + + const deleteMutation = `mutation { + deletePerformance(input: { + id: "P1" + }) { + id + } + } + `; + + // Delete as non-admin user, should fail + const response9 = await GRAPHQL_CLIENT_3.query(deleteMutation, {}); + + expect(response9.data.deletePerformance).toBeNull(); + expect(response9.errors.length).toEqual(1); + expect((response9.errors[0] as any).errorType).toEqual('Unauthorized'); + + // Delete as Admin, should succeed + const response10 = await GRAPHQL_CLIENT_1.query(deleteMutation, {}); + + expect(response10.data.deletePerformance).toBeDefined(); + expect(response10.data.deletePerformance.id).toEqual('P1'); + }); + + test('Test authorized user can get Performance with no created stage', async () => { + const createPerf = `mutation { + create: createPerformance(input: { + id: "P3" + performer: "Perf #3" + description: "desc" + time: "2021-11-11T00:00:00Z" + }) { + id + performer + description + time + createdAt + updatedAt + } + }`; + + const getPerf = `query { + g1: getPerformance(id: "P3") { + id + performer + description + time + stage { + id + name + createdAt + updatedAt + } + createdAt + updatedAt + } + } + `; + + const createStage = `mutation { + createStage(input: {name: "stage3", id: "003"}) { + createdAt + id + name + updatedAt + } + }`; + + const updatePerf = `mutation { + u1: updatePerformance(input: {id: "P3", performanceStageId: "003"}) { + createdAt + description + id + performer + time + updatedAt + stage { + id + name + } + } + }`; + + // first make a query to the record 'P3' + const response1 = await GRAPHQL_CLIENT_1.query(getPerf, {}); + expect(response1).toBeDefined(); + expect(response1.data.g1).toBeNull(); + + // create performance and expect stage to be null + await GRAPHQL_CLIENT_1.query(createPerf, {}); + const response2 = await GRAPHQL_CLIENT_1.query(getPerf, {}); + expect(response2).toBeDefined(); + expect(response2.data.g1).toBeDefined(); + expect(response2.data.g1.id).toEqual('P3'); + expect(response2.data.g1.description).toEqual('desc'); + expect(response2.data.g1.stage).toBeNull(); + + //create stage and then add it to perf should show stage in perf + await GRAPHQL_CLIENT_1.query(createStage, {}); + const response3 = await GRAPHQL_CLIENT_1.query(updatePerf, {}); + expect(response3).toBeDefined(); + expect(response3.data.u1).toBeDefined(); + expect(response3.data.u1.id).toEqual('P3'); + expect(response3.data.u1.stage).toMatchObject({ + id: '003', + name: 'stage3', + }); + }); +}); diff --git a/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts b/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts index 2f13e615b2d..8970de56761 100644 --- a/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts +++ b/packages/graphql-transformers-e2e-tests/src/deployNestedStacks.ts @@ -178,7 +178,7 @@ export async function deploy( } function addAPIKeys(stack: DeploymentResources) { - if (!stack.rootStack.Resources.GraphQLAPIKey) { + if (stack.rootStack.Parameters.CreateAPIKey && !stack.rootStack.Resources.GraphQLAPIKey) { stack.rootStack.Resources.GraphQLAPIKey = { Type: 'AWS::AppSync::ApiKey', Properties: { @@ -189,7 +189,7 @@ function addAPIKeys(stack: DeploymentResources) { }; } - if (!stack.rootStack.Outputs.GraphQLAPIKeyOutput) { + if (stack.rootStack.Parameters.CreateAPIKey && !stack.rootStack.Outputs.GraphQLAPIKeyOutput) { stack.rootStack.Outputs.GraphQLAPIKeyOutput = { Value: { 'Fn::GetAtt': ['GraphQLAPIKey', 'ApiKey'],