Skip to content

Commit

Permalink
feat: headless command for geo -- map (#8403)
Browse files Browse the repository at this point in the history
* feat: headless command for geo

* feat: add headless support for update map

* fix: lgtm alert

* test: add unit tests for geo headless validator

* fix: duplicate import

* fix: refactor methods and add check for exisitence

* fix: move existence check

* test: restructure unit tests
  • Loading branch information
AaronZyLee committed Nov 2, 2021
1 parent 11e4ae7 commit 73793b4
Show file tree
Hide file tree
Showing 17 changed files with 479 additions and 25 deletions.
4 changes: 3 additions & 1 deletion packages/amplify-category-geo/package.json
Expand Up @@ -36,7 +36,9 @@
"lodash": "^4.17.19",
"mime-types": "^2.1.26",
"promise-sequential": "^1.1.1",
"uuid": "^8.3.2"
"uuid": "^8.3.2",
"amplify-util-headless-input": "1.5.4",
"amplify-headless-interface": "1.10.0"
},
"jest": {
"collectCoverage": true,
Expand Down
21 changes: 20 additions & 1 deletion packages/amplify-category-geo/src/index.ts
Expand Up @@ -8,6 +8,7 @@ import * as helpCommand from './commands/geo/help';
import { getServicePermissionPolicies } from './service-utils/resourceUtils';
import { ServiceName } from './service-utils/constants';
import { printer } from 'amplify-prompts';
import { addResourceHeadless, updateResourceHeadless } from './provider-controllers';

export const executeAmplifyCommand = async (context: $TSContext) => {
switch (context.input.command) {
Expand Down Expand Up @@ -59,5 +60,23 @@ export const getPermissionPolicies = (context: $TSContext, resourceOpsMapping: $
}
});

return { permissionPolicies, resourceAttributes };
return { permissionPolicies, resourceAttributes };
}

/**
* Entry point for headless commands
* @param {any} context The amplify context object
* @param {string} headlessPayload The serialized payload from the platform
*/
export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => {
switch (context.input.command) {
case 'add':
await addResourceHeadless(context, headlessPayload);
break;
case 'update':
await updateResourceHeadless(context, headlessPayload);
break;
default:
printer.error(`Headless mode for ${context.input.command} geo is not implemented yet`);
}
};
54 changes: 52 additions & 2 deletions packages/amplify-category-geo/src/provider-controllers/index.ts
Expand Up @@ -3,10 +3,13 @@ import { ServiceName, provider } from '../service-utils/constants';
import { $TSObject, open, stateManager } from 'amplify-cli-core';
import { $TSContext } from 'amplify-cli-core';
import { addPlaceIndexResource, updatePlaceIndexResource, removePlaceIndexResource } from './placeIndex';
import { addMapResource, updateMapResource, removeMapResource } from './map';
import { addMapResource, updateMapResource, removeMapResource, addMapResourceHeadless, updateMapResourceHeadless } from './map';
import { printer, prompter } from 'amplify-prompts';
import { getServiceFriendlyName } from '../service-walkthroughs/resourceWalkthrough';
import { TemplateMappings } from '../service-stacks/baseStack';
import { validateAddGeoRequest, validateUpdateGeoRequest } from 'amplify-util-headless-input';
import { MapConfiguration, MapModification } from 'amplify-headless-interface';
import { checkGeoResourceExists } from '../service-utils/resourceUtils';

/**
* Entry point for creating a new Geo resource
Expand Down Expand Up @@ -105,7 +108,7 @@ const badServiceError = (service: string) => {
};

export const insufficientInfoForUpdateError = (service: ServiceName) => {
new Error(`Insufficient information to update ${getServiceFriendlyName(service)}. Please re-try and provide all inputs.`);
return new Error(`Insufficient information to update ${getServiceFriendlyName(service)}. Please re-try and provide all inputs.`);
};

export const getTemplateMappings = async (context: $TSContext): Promise<TemplateMappings> => {
Expand All @@ -122,3 +125,50 @@ export const getTemplateMappings = async (context: $TSContext): Promise<Template
});
return Mappings;
};

/**
* Entry point for headless command of creating a new Geo resource
*/
export const addResourceHeadless = async (
context: $TSContext,
headlessPayload: string
): Promise<string | undefined> => {
if(!projectHasAuth()) {
throw new Error('Please add auth (Amazon Cognito) to your project using "amplify add auth"');
}
const { serviceConfiguration } = await validateAddGeoRequest(headlessPayload);
const { serviceName,name } = serviceConfiguration;
if (await checkGeoResourceExists(name)) {
throw new Error(`Geo resource with name '${name}' already exists.`)
}
switch (serviceName) {
case ServiceName.Map:
return addMapResourceHeadless(context, serviceConfiguration as MapConfiguration);
default:
throw badHeadlessServiceError(serviceName);
}
};

/**
* Entry point for headless command of updating an existing Geo resource
*/
export const updateResourceHeadless = async (
context: $TSContext,
headlessPayload: string
): Promise<string | undefined> => {
const { serviceModification } = await validateUpdateGeoRequest(headlessPayload);
const { serviceName, name } = serviceModification;
if (!await checkGeoResourceExists(name)) {
throw new Error(`Geo resource with name '${name}' does not exist.`)
}
switch (serviceName) {
case ServiceName.Map:
return updateMapResourceHeadless(context, serviceModification as MapModification);
default:
throw badHeadlessServiceError(serviceName);
}
};

const badHeadlessServiceError = (service: string) => {
return new Error(`Headless mode for service type ${service} is not supported`);
}
86 changes: 65 additions & 21 deletions packages/amplify-category-geo/src/provider-controllers/map.ts
Expand Up @@ -7,6 +7,9 @@ import { $TSAny, $TSContext } from 'amplify-cli-core';
import { printNextStepsSuccessMessage, setProviderContext, insufficientInfoForUpdateError } from './index';
import { ServiceName } from '../service-utils/constants';
import { printer } from 'amplify-prompts';
import { getMapStyleComponents } from '../service-utils/mapParams';
import { MapConfiguration, MapModification } from 'amplify-headless-interface';
import { checkAnyGeoResourceExists, checkGeoResourceExists } from '../service-utils/resourceUtils';

export const addMapResource = async (
context: $TSContext
Expand All @@ -17,13 +20,7 @@ export const addMapResource = async (
};
// populate the parameters for the resource
await createMapWalkthrough(context, mapParams);
const completeParameters: MapParameters = convertToCompleteMapParams(mapParams);

await createMapResource(context, completeParameters);

printer.success(`Successfully added resource ${completeParameters.name} locally.`);
printNextStepsSuccessMessage(context);
return completeParameters.name;
return await addMapResourceWithParams(context, mapParams)
};

export const updateMapResource = async (
Expand All @@ -35,20 +32,7 @@ export const updateMapResource = async (
};
// populate the parameters for the resource
await updateMapWalkthrough(context, mapParams);

if (mapParams.name && mapParams.isDefault !== undefined && mapParams.accessType) {
modifyMapResource(context, {
accessType: mapParams.accessType,
name: mapParams.name,
isDefault: mapParams.isDefault
});
} else {
throw insufficientInfoForUpdateError(ServiceName.Map);
}

printer.success(`Successfully updated resource ${mapParams.name} locally.`);
printNextStepsSuccessMessage(context);
return mapParams.name;
return await updateMapResourceWithParams(context, mapParams);
};

export const removeMapResource = async (
Expand Down Expand Up @@ -82,3 +66,63 @@ export const removeMapResource = async (
printNextStepsSuccessMessage(context);
return resourceToRemove;
};

export const addMapResourceHeadless = async (
context: $TSContext,
config: MapConfiguration
): Promise<string> => {
// initialize the Map parameters
let mapParams: Partial<MapParameters> = {
providerContext: setProviderContext(context, ServiceName.Map),
name: config.name,
accessType: config.accessType,
pricingPlan: config.pricingPlan,
isDefault: config.setAsDefault,
...getMapStyleComponents(config.mapStyle)
};

return await addMapResourceWithParams(context, mapParams);
}

export const updateMapResourceHeadless = async (
context: $TSContext,
config: MapModification
): Promise<string> => {
// initialize the Map parameters
let mapParams: Partial<MapParameters> = {
providerContext: setProviderContext(context, ServiceName.Map),
name: config.name,
accessType: config.accessType,
isDefault: config.setAsDefault,
};
return await updateMapResourceWithParams(context, mapParams);
}

export const addMapResourceWithParams = async (
context: $TSContext,
mapParams: Partial<MapParameters>
): Promise<string> => {
const completeParameters: MapParameters = convertToCompleteMapParams(mapParams);
await createMapResource(context, completeParameters);
printer.success(`Successfully added resource ${completeParameters.name} locally.`);
printNextStepsSuccessMessage(context);
return completeParameters.name;
}

export const updateMapResourceWithParams = async (
context: $TSContext,
mapParams: Partial<MapParameters>
): Promise<string> => {
if (mapParams.name && mapParams.isDefault !== undefined && mapParams.accessType) {
modifyMapResource(context, {
accessType: mapParams.accessType,
name: mapParams.name,
isDefault: mapParams.isDefault
});
} else {
throw insufficientInfoForUpdateError(ServiceName.Map);
}
printer.success(`Successfully updated resource ${mapParams.name} locally.`);
printNextStepsSuccessMessage(context);
return mapParams.name;
}
@@ -0,0 +1,93 @@
{
"description": "Defines the json object expected by `amplify add geo --headless` with map service",
"type": "object",
"properties": {
"version": {
"description": "The schema version.",
"type": "number",
"enum": [
1
]
},
"serviceConfiguration": {
"description": "The service configuration that will be interpreted by Amplify.",
"oneOf": [
{"$ref": "#/definitions/MapServiceConfiguration"}
]
}
},
"required": [
"serviceConfiguration",
"version"
],
"definitions": {
"MapServiceConfiguration": {
"description": "Configuration exposed by Map.",
"type": "object",
"properties": {
"serviceName": {
"description": "The service name of the resource provider.",
"type": "string",
"enum": [
"Map"
]
},
"name": {
"description": "The name of the map that will be created.",
"type": "string"
},
"mapStyle": {
"description": "The map style type.",
"type": "string",
"enum": [
"VectorEsriNavigation",
"VectorEsriStreets",
"VectorEsriTopographic",
"VectorEsriDarkGrayCanvas",
"VectorEsriLightGrayCanvas",
"VectorHereBerlin"
]
},
"pricingPlan": {
"$ref": "#/definitions/PricingPlan"
},
"accessType": {
"$ref": "#/definitions/AccessType"
},
"setAsDefault": {
"$ref": "#/definitions/SetAsDefault"
}
},
"required": [
"serviceName",
"name",
"mapStyle",
"accessType",
"pricingPlan",
"setAsDefault"
]
},
"PricingPlan": {
"description": "The pricing plan for amazon location service.",
"type": "string",
"enum": [
"RequestBasedUsage",
"MobileAssetTracking",
"MobileAssetManagement"
]
},
"AccessType": {
"description": "The access policy for geo resources.",
"type": "string",
"enum": [
"AuthorizedUsers",
"AuthorizedAndGuestUsers"
]
},
"SetAsDefault": {
"description": "Whether the geo resource added is set to default.",
"type": "boolean"
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
@@ -0,0 +1,66 @@
{
"type": "object",
"properties": {
"version": {
"description": "The schema version.",
"type": "number",
"enum": [
1
]
},
"serviceModification": {
"description": "Service modifications that will be interpreted by Amplify.",
"oneOf": [
{"$ref": "#/definitions/MapModification"}
]
}
},
"required": [
"serviceModification",
"version"
],
"definitions": {
"MapModification": {
"description": "Modification exposed by Map.",
"type": "object",
"properties": {
"serviceName": {
"description": "The service name of the resource provider.",
"type": "string",
"enum": [
"Map"
]
},
"name": {
"description": "The name of the map that will be modified.",
"type": "string"
},
"accessType": {
"$ref": "#/definitions/AccessType"
},
"setAsDefault": {
"$ref": "#/definitions/SetAsDefault"
}
},
"required": [
"serviceName",
"name",
"accessType",
"setAsDefault"
]
},
"AccessType": {
"description": "The access policy for geo resources.",
"type": "string",
"enum": [
"AuthorizedUsers",
"AuthorizedAndGuestUsers"
]
},
"SetAsDefault": {
"description": "Whether the geo resource added is set to default.",
"type": "boolean"
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
2 changes: 2 additions & 0 deletions packages/amplify-headless-interface/src/index.ts
Expand Up @@ -4,3 +4,5 @@ export * from './interface/auth/add';
export * from './interface/auth/update';
export * from './interface/auth/import';
export * from './interface/storage';
export * from './interface/geo/add';
export * from './interface/geo/update';

0 comments on commit 73793b4

Please sign in to comment.