├── .gitignore ├── tests ├── Application.cfc ├── runner.cfm └── specs │ └── dynamodb.cfc ├── ModuleConfig.cfc ├── LICENSE ├── box.json ├── services ├── elasticsearch.cfc ├── translate.cfc ├── personalizeEvents.cfc ├── cognitoIdentity.cfc ├── ssm.cfc ├── personalizeruntime.cfc ├── elastictranscoder.cfc ├── ses.cfc ├── polly.cfc ├── autoscaling.cfc ├── kms.cfc ├── rekognition.cfc ├── ec2.cfc ├── secretsmanager.cfc ├── sns.cfc ├── sqs.cfc ├── connect.cfc └── personalize.cfc ├── com ├── httpLucee.cfc ├── httpColdFusion.cfc ├── utils.cfc ├── api.cfc ├── signature_v4.cfc └── credentials.cfc ├── .cfformat.json ├── aws.cfc └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | testbox/ 2 | .vscode 3 | -------------------------------------------------------------------------------- /tests/Application.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | rootPath = getDirectoryFromPath( getCurrentTemplatePath() ) 4 | .replace( '\', '/', 'all' ) 5 | .replaceNoCase( 'tests/', '' ); 6 | 7 | this.mappings[ '/tests' ] = rootPath & '/tests'; 8 | 9 | public boolean function onRequestStart( 10 | String targetPage 11 | ) { 12 | setting requestTimeout="9999"; 13 | return true; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /tests/runner.cfm: -------------------------------------------------------------------------------- 1 | 2 | 3 | testbox = new testbox.system.Testbox(); 4 | param name="url.reporter" default="simple"; 5 | param name="url.directory" default="tests.specs"; 6 | args = { reporter: url.reporter, directory: url.directory }; 7 | if ( structKeyExists( url, 'bundles' ) ) args.bundles = url.bundles; 8 | results = testBox.run( argumentCollection = args ); 9 | 10 | 11 | 12 | #trim( results )# 13 | -------------------------------------------------------------------------------- /ModuleConfig.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | this.title = 'AWS CFML'; 4 | this.author = 'John Berquist'; 5 | this.webURL = 'https://github.com/jcberquist/aws-cfml'; 6 | this.description = 'This module will provide you with connectivity to the AWS API for any ColdFusion (CFML) application.'; 7 | 8 | /** 9 | * See README.md for the config struct options 10 | */ 11 | function configure() { 12 | settings = { 13 | awsKey: '', 14 | awsSecretKey: '', 15 | defaultRegion: '', 16 | constructorArgs: { } 17 | }; 18 | } 19 | 20 | function onLoad() { 21 | binder 22 | .map( 'aws@awscfml' ) 23 | .to( '#moduleMapping#.aws' ) 24 | .asSingleton() 25 | .initWith( argumentCollection = settings ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "author":"John Berquist", 3 | "bugs":"https://github.com/jcberquist/aws-cfml/issues", 4 | "changelog":"", 5 | "description":"", 6 | "devDependencies":{ 7 | "testbox":"^2.8.0+191" 8 | }, 9 | "engines":[ 10 | { 11 | "type":"lucee", 12 | "version":">=4.5.x" 13 | }, 14 | { 15 | "type":"adobe", 16 | "version":">=11.0.0" 17 | } 18 | ], 19 | "homepage":"https://github.com/jcberquist/aws-cfml", 20 | "installPaths":{ 21 | "testbox":"testbox/" 22 | }, 23 | "instructions":"", 24 | "keywords":[ 25 | "aws", 26 | "APIs" 27 | ], 28 | "license":[ 29 | { 30 | "type":"MIT", 31 | "URL":"http://opensource.org/licenses/MIT" 32 | } 33 | ], 34 | "location":"jcberquist/aws-cfml#v1.36.0", 35 | "name":"aws-cfml", 36 | "packageDirectory":"awscfml", 37 | "private":false, 38 | "projectURL":"", 39 | "shortDescription":"AWS CFML is a CFML library for interacting with AWS APIs", 40 | "slug":"aws-cfml", 41 | "type":"modules", 42 | "version":"1.36.0" 43 | } 44 | -------------------------------------------------------------------------------- /services/elasticsearch.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'es'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.defaultEndPoint = arguments.settings.endpoint; 11 | return this; 12 | } 13 | 14 | public any function apiCall( 15 | string httpMethod = 'GET', 16 | string path = '/', 17 | struct queryParams = { }, 18 | struct headers = { }, 19 | any payload = '' 20 | ) { 21 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 22 | if ( !structKeyExists( arguments, 'EndPoint' ) ) arguments.EndPoint = variables.defaultEndPoint; 23 | 24 | var host = endPoint & '.' & requestSettings.region & '.' & variables.service & '.amazonaws.com'; 25 | 26 | var result = api.call( 27 | variables.service, 28 | host, 29 | requestSettings.region, 30 | httpMethod, 31 | path, 32 | queryParams, 33 | headers, 34 | payload, 35 | requestSettings.awsCredentials 36 | ); 37 | if ( result.keyExists( 'rawData' ) && isJSON( result.rawData ) ) { 38 | result[ 'data' ] = deserializeJSON( result.rawData ); 39 | } 40 | return result; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /com/httpLucee.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | public any function init( 4 | required any utils, 5 | struct httpProxy = { server: '', port: 80 } 6 | ) { 7 | variables.utils = utils; 8 | variables.httpProxy = httpProxy; 9 | return this; 10 | } 11 | 12 | public any function makeHttpRequest( 13 | required string httpMethod, 14 | required string path, 15 | struct queryParams = { }, 16 | struct headers = { }, 17 | any body, 18 | boolean useSSL = true, 19 | numeric timeout = 50 20 | ) { 21 | var result = ''; 22 | var fullPath = path & ( !queryParams.isEmpty() ? ( '?' & utils.parseQueryParams( queryParams ) ) : '' ); 23 | var request_headers = utils.parseHeaders( headers ); 24 | var urlPath = 'http' & ( useSSL ? 's' : '' ) & '://' & fullPath; 25 | 26 | http 27 | url=urlPath 28 | method=httpMethod 29 | result="result" 30 | encodeurl=false 31 | timeout=timeout 32 | proxyServer=httpProxy.server 33 | proxyPort=httpProxy.port { 34 | for ( var header in request_headers ) { 35 | if ( header.name == 'host' ) continue; 36 | httpparam type="header" name=lCase( header.name ) value=header.value; 37 | } 38 | 39 | if ( arrayFindNoCase( [ 'POST', 'PUT' ], httpMethod ) && !isNull( arguments.body ) ) { 40 | httpparam type="body" value=body; 41 | } 42 | } 43 | return result; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /com/httpColdFusion.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | public any function init( 4 | required any utils, 5 | struct httpProxy = { server: '', port: 80 } 6 | ) { 7 | variables.utils = utils; 8 | variables.httpProxy = httpProxy; 9 | return this; 10 | } 11 | 12 | public any function makeHttpRequest( 13 | required string httpMethod, 14 | required string path, 15 | struct queryParams = { }, 16 | struct headers = { }, 17 | any body, 18 | boolean useSSL = true, 19 | numeric timeout = 50 20 | ) { 21 | var result = ''; 22 | var fullPath = path & ( !queryParams.isEmpty() ? ( '?' & utils.parseQueryParams( queryParams ) ) : '' ); 23 | var request_headers = utils.parseHeaders( headers ); 24 | var urlPath = 'http' & ( useSSL ? 's' : '' ) & '://' & fullPath; 25 | 26 | cfhttp( 27 | url = urlPath, 28 | method = httpMethod, 29 | result = "result", 30 | timeout = timeout, 31 | proxyserver = httpProxy.server, 32 | proxyport = httpProxy.port 33 | ) { 34 | for ( var header in request_headers ) { 35 | if ( header.name == 'host' ) continue; 36 | cfhttpparam( type = "header", name = lCase( header.name ), value = header.value ); 37 | } 38 | 39 | if ( arrayFindNoCase( [ 'POST', 'PUT' ], httpMethod ) && !isNull( arguments.body ) ) { 40 | cfhttpparam( type = "body", value = body ); 41 | } 42 | } 43 | return result; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /tests/specs/dynamodb.cfc: -------------------------------------------------------------------------------- 1 | component extends=testbox.system.BaseSpec { 2 | 3 | function beforeAll() { 4 | dynamodb = new aws( 'public_key', 'private_key' ).dynamodb; 5 | makePublic( dynamodb, 'toJSON' ); 6 | } 7 | 8 | function run() { 9 | describe( 'the toJSON() method', function() { 10 | it( 'correctly serializes the string type', function() { 11 | var data = { 'test_string': { 'S': '123' } }; 12 | var expected_json = '{"test_string":{"S":"123"}}'; 13 | expect( dynamodb.toJSON( data ) ).toBe( expected_json ); 14 | } ); 15 | 16 | it( 'correctly serializes the number type', function() { 17 | var data = { 'test_number': { 'N': '123' } }; 18 | var expected_json = '{"test_number":{"N":"123"}}'; 19 | expect( dynamodb.toJSON( data ) ).toBe( expected_json ); 20 | } ); 21 | 22 | it( 'correctly serializes the null type', function() { 23 | var data = { 'test_null': { 'NULL': 'true' } }; 24 | var expected_json = '{"test_null":{"NULL":"true"}}'; 25 | expect( dynamodb.toJSON( data ) ).toBe( expected_json ); 26 | } ); 27 | 28 | it( 'correctly serializes the boolean type', function() { 29 | var data = { 'test_bool': { 'BOOL': 'false' } }; 30 | var expected_json = '{"test_bool":{"BOOL":"false"}}'; 31 | expect( dynamodb.toJSON( data ) ).toBe( expected_json ); 32 | } ); 33 | } ); 34 | 35 | describe( 'the encodeValues() method', function() { 36 | it( 'correctly types nested map key values', function() { 37 | var data = { 'a': { 'b': 1, 'c': { 'b': javacast( 'null', '' ) } } }; 38 | var typeDefinitions = { 'b': 'S' }; 39 | var expected_struct = { a: { M: { b: { S: '1' }, c: { M: { b: { NULL: true } } } } } }; 40 | expect( dynamodb.encodeValues( data, typeDefinitions ) ).toBe( expected_struct ); 41 | } ); 42 | } ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /services/translate.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'translate'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | variables.defaultSourceLanguageCode = arguments.settings.defaultSourceLanguageCode; 12 | variables.defaultTargetLanguageCode = arguments.settings.defaultTargetLanguageCode; 13 | return this; 14 | } 15 | 16 | public any function translateText( 17 | required string Text, 18 | string SourceLanguageCode = defaultSourceLanguageCode, 19 | string TargetLanguageCode = defaultTargetLanguageCode 20 | ) { 21 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 22 | var payload = { 23 | 'Text': Text, 24 | 'SourceLanguageCode': SourceLanguageCode, 25 | 'TargetLanguageCode': TargetLanguageCode 26 | }; 27 | return apiCall( requestSettings, 'TranslateText', payload ); 28 | } 29 | 30 | public string function getHost( 31 | required string region 32 | ) { 33 | return variables.service & '.' & region & '.amazonaws.com'; 34 | } 35 | 36 | private any function apiCall( 37 | required struct requestSettings, 38 | required string target, 39 | struct payload = { } 40 | ) { 41 | var host = getHost( requestSettings.region ); 42 | var payloadString = serializeJSON( payload ); 43 | 44 | var headers = { }; 45 | headers[ 'X-Amz-Target' ] = 'AWSShineFrontendService_' & variables.apiVersion & '.' & arguments.target; 46 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 47 | 48 | var apiResponse = api.call( 49 | variables.service, 50 | host, 51 | requestSettings.region, 52 | 'POST', 53 | '/', 54 | { }, 55 | headers, 56 | payloadString, 57 | requestSettings.awsCredentials 58 | ); 59 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 60 | 61 | return apiResponse; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /.cfformat.json: -------------------------------------------------------------------------------- 1 | { 2 | "array.empty_padding": true, 3 | "array.multiline.element_count": 4, 4 | "array.multiline.leading_comma": false, 5 | "array.multiline.leading_comma.padding": true, 6 | "array.multiline.min_length": 40, 7 | "array.padding": true, 8 | "binary_operators.padding": true, 9 | "brackets.padding": true, 10 | "comment.asterisks": "indent", 11 | "for_loop_semicolons.padding": true, 12 | "function_anonymous.empty_padding": false, 13 | "function_anonymous.group_to_block_spacing": "spaced", 14 | "function_anonymous.multiline.element_count": 4, 15 | "function_anonymous.multiline.leading_comma": false, 16 | "function_anonymous.multiline.leading_comma.padding": true, 17 | "function_anonymous.multiline.min_length": 40, 18 | "function_anonymous.padding": true, 19 | "function_call.empty_padding": false, 20 | "function_call.multiline.element_count": 4, 21 | "function_call.multiline.leading_comma": false, 22 | "function_call.multiline.leading_comma.padding": true, 23 | "function_call.multiline.min_length": 40, 24 | "function_call.padding": true, 25 | "function_declaration.empty_padding": false, 26 | "function_declaration.group_to_block_spacing": "spaced", 27 | "function_declaration.multiline.element_count": 0, 28 | "function_declaration.multiline.leading_comma": false, 29 | "function_declaration.multiline.leading_comma.padding": true, 30 | "function_declaration.multiline.min_length": 0, 31 | "function_declaration.padding": true, 32 | "indent_size": 4, 33 | "keywords.block_to_keyword_spacing": "spaced", 34 | "keywords.empty_group_spacing": false, 35 | "keywords.group_to_block_spacing": "spaced", 36 | "keywords.padding_inside_group": true, 37 | "keywords.spacing_to_block": "spaced", 38 | "keywords.spacing_to_group": true, 39 | "max_columns": 120, 40 | "parentheses.padding": true, 41 | "strings.attributes.quote": "double", 42 | "strings.quote": "single", 43 | "struct.empty_padding": true, 44 | "struct.multiline.element_count": 4, 45 | "struct.multiline.leading_comma": false, 46 | "struct.multiline.leading_comma.padding": true, 47 | "struct.multiline.min_length": 40, 48 | "struct.padding": true, 49 | "struct.separator": ": ", 50 | "tab_indent": false 51 | } 52 | -------------------------------------------------------------------------------- /services/personalizeEvents.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'personalize-events'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /** 15 | * Records user interaction event data. 16 | * https://docs.aws.amazon.com/personalize/latest/dg/API_UBS_PutEvents.html 17 | * @eventList required array: A list of event data from the session. Array of Event objects (https://docs.aws.amazon.com/personalize/latest/dg/API_UBS_Event.html) 18 | * @sessionId required string: The session ID associated with the user's visit. 19 | * @trackingId required string: The tracking ID for the event. The ID is generated by a call to the CreateEventTracker API. 20 | * @userId required string: The user associated with the event. 21 | */ 22 | public any function putEvents( 23 | required array eventList, 24 | required string sessionId, 25 | required string trackingId, 26 | required string userId 27 | ) { 28 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 29 | var args = { 30 | 'eventList': arguments.eventList, 31 | 'sessionId': arguments.sessionId, 32 | 'trackingId': arguments.trackingId, 33 | 'userId': arguments.userId 34 | }; 35 | 36 | return apiCall( 37 | requestSettings, 38 | 'PutEvents', 39 | '/events', 40 | args 41 | ); 42 | } 43 | 44 | private any function apiCall( 45 | required struct requestSettings, 46 | required string target, 47 | required string path, 48 | struct payload = { } 49 | ) { 50 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 51 | 52 | var payloadString = serializeJSON( payload ); 53 | var headers = { }; 54 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 55 | 56 | var apiResponse = api.call( 57 | 'personalize', 58 | host, 59 | requestSettings.region, 60 | 'POST', 61 | arguments.path, 62 | { }, 63 | headers, 64 | payloadString, 65 | requestSettings.awsCredentials 66 | ); 67 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 68 | 69 | return apiResponse; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /services/cognitoIdentity.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'cognito-identity'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /* 15 | * Returns an IdentityId and a Token 16 | * https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetOpenIdTokenForDeveloperIdentity.html 17 | * @IdentityPoolId An identity pool ID in the format REGION:GUID. 18 | * @Logins A set of optional name-value pairs that map provider names to provider tokens. 19 | * @IdentityId A unique identifier in the format REGION:GUID. 20 | * @TokenDuration The expiration time of the token, in seconds. 21 | */ 22 | public any function GetOpenIdTokenForDeveloperIdentity( 23 | required string IdentityPoolId, 24 | required struct Logins, 25 | string IdentityId, 26 | numeric TokenDuration 27 | ) { 28 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 29 | var payload = { 'IdentityPoolId': arguments.IdentityPoolId, 'Logins': arguments.Logins }; 30 | 31 | if ( !isNull( arguments.IdentityId ) ) payload[ 'IdentityId' ] = arguments.IdentityId; 32 | if ( !isNull( arguments.TokenDuration ) ) payload[ 'TokenDuration' ] = arguments.TokenDuration; 33 | 34 | return apiCall( requestSettings, 'GetOpenIdTokenForDeveloperIdentity', payload ); 35 | } 36 | 37 | // private functions 38 | 39 | private any function apiCall( 40 | required struct requestSettings, 41 | required string target, 42 | struct payload = { } 43 | ) { 44 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 45 | var payloadString = payload.isEmpty() ? '' : serializeJSON( payload ); 46 | var headers = { }; 47 | headers[ 'X-Amz-Target' ] = 'AWSCognitoIdentityService.#target#'; 48 | if ( !payload.isEmpty() ) headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 49 | 50 | var apiResponse = api.call( 51 | variables.service, 52 | host, 53 | requestSettings.region, 54 | 'POST', 55 | '/', 56 | { }, 57 | headers, 58 | payloadString, 59 | requestSettings.awsCredentials 60 | ); 61 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 62 | 63 | return apiResponse; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /aws.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | // Docs: https://github.com/jcberquist/aws-cfml 4 | 5 | variables.services = [ 6 | 'autoscaling', 7 | 'connect', 8 | 'cognitoIdentity', 9 | 'dynamodb', 10 | 'ec2', 11 | 'elasticsearch', 12 | 'elastictranscoder', 13 | 'kms', 14 | 'personalize', 15 | 'personalizeEvents', 16 | 'personalizeRuntime', 17 | 'polly', 18 | 'rekognition', 19 | 's3', 20 | 'secretsmanager', 21 | 'ses', 22 | 'sns', 23 | 'sqs', 24 | 'ssm', 25 | 'translate' 26 | ]; 27 | 28 | variables.constructorArgs = { 29 | autoscaling: { apiVersion: '2011-01-01' }, 30 | connect: { }, 31 | cognitoIdentity: { apiVersion: '2014-06-30' }, 32 | dynamodb: { apiVersion: '20120810' }, 33 | elastictranscoder: { apiVersion: '2012-09-25' }, 34 | elasticsearch: { endpoint: '' }, 35 | kms: { apiVersion: '2014-11-01' }, 36 | personalize: { apiVersion: '2018-05-22' }, 37 | personalizeRuntime: { apiVersion: '2018-05-22' }, 38 | personalizeEvents: { apiVersion: '2018-03-22' }, 39 | polly: { apiVersion: '2016-06-10', defaultLanguageCode: 'en-US', defaultEngine: 'standard' }, 40 | rekognition: { apiVersion: '2016-06-27' }, 41 | s3: { host: '', useSSL: true }, 42 | secretsmanager: { apiVersion: '2017-10-17' }, 43 | ses: { apiVersion: '2010-12-01' }, 44 | sns: { apiVersion: '2010-03-31' }, 45 | ssm: { apiVersion: '2014-11-06' }, 46 | sqs: { apiVersion: '2012-11-05' }, 47 | translate: { apiVersion: '20170701', defaultSourceLanguageCode: 'es', defaultTargetLanguageCode: 'en' }, 48 | ec2: { apiVersion: '2016-11-15' } 49 | }; 50 | 51 | public struct function init( 52 | string awsKey = '', 53 | string awsSecretKey = '', 54 | string defaultRegion = '', 55 | struct constructorArgs = { }, 56 | struct httpProxy = { server: '', port: 80 }, 57 | string libraryMapping = '' 58 | ) { 59 | if ( len( arguments.libraryMapping ) && mid( arguments.libraryMapping, len( arguments.libraryMapping ), 1 ) != '.' ) { 60 | arguments.libraryMapping &= '.'; 61 | } 62 | 63 | this.api = new '#arguments.libraryMapping#com.api'( 64 | awsKey, 65 | awsSecretKey, 66 | defaultRegion, 67 | httpProxy, 68 | libraryMapping 69 | ); 70 | 71 | for ( var service in variables.services ) { 72 | if ( structKeyExists( arguments.constructorArgs, service ) ) { 73 | structAppend( variables.constructorArgs[ service ], arguments.constructorArgs[ service ] ); 74 | } 75 | this[ service ] = new '#arguments.libraryMapping#services.#service#'( 76 | this.api, variables.constructorArgs[ service ] 77 | ); 78 | } 79 | 80 | return this; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /services/ssm.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'ssm'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /** 15 | * Get information about a parameter by using the parameter name. Don't confuse this API action with the GetParameters API action. 16 | * https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_GetParameter.html 17 | * @Name The name of the parameter you want to query. 18 | * @WithDecryption Return decrypted values for secure string parameters. This flag is ignored for String and StringList parameter types. 19 | */ 20 | public any function getParameter( 21 | required string Name, 22 | boolean WithDecryption 23 | ) { 24 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 25 | var payload = { 'Name': arguments.Name }; 26 | if ( !isNull( arguments.WithDecryption ) ) { 27 | payload[ 'WithDecryption' ] = arguments.WithDecryption; 28 | } 29 | return apiCall( requestSettings, 'GetParameter', payload ); 30 | } 31 | 32 | /** 33 | * Get details of a parameter. Don't confuse this API action with the GetParameter API action. 34 | * https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_GetParameters.html 35 | * @Names Names of the parameters for which you want to query information. 36 | * @WithDecryption Return decrypted secure string value. Return decrypted values for secure string parameters. This flag is ignored for String and StringList parameter types. 37 | */ 38 | public any function getParameters( 39 | required array Names, 40 | boolean WithDecryption 41 | ) { 42 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 43 | var payload = { 'Names': arguments.Names }; 44 | if ( !isNull( arguments.WithDecryption ) ) { 45 | payload[ 'WithDecryption' ] = arguments.WithDecryption; 46 | } 47 | return apiCall( requestSettings, 'GetParameters', payload ); 48 | } 49 | 50 | public string function getHost( 51 | required string region 52 | ) { 53 | return variables.service & '.' & region & '.amazonaws.com'; 54 | } 55 | 56 | private any function apiCall( 57 | required struct requestSettings, 58 | required string target, 59 | struct payload = { } 60 | ) { 61 | var host = getHost( requestSettings.region ); 62 | var payloadString = serializeJSON( payload ); 63 | 64 | var headers = { }; 65 | headers[ 'X-Amz-Target' ] = 'AmazonSSM' & '.' & arguments.target; 66 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 67 | 68 | var apiResponse = api.call( 69 | variables.service, 70 | host, 71 | requestSettings.region, 72 | 'POST', 73 | '/', 74 | { }, 75 | headers, 76 | payloadString, 77 | requestSettings.awsCredentials 78 | ); 79 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 80 | 81 | return apiResponse; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /services/personalizeruntime.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'personalize-runtime'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /** 15 | * Returns a list of recommended items. The required input depends on the recipe type used to create the solution backing the campaign, as follows: 16 | RELATED_ITEMS - itemId required, userId not used 17 | USER_PERSONALIZATION - itemId optional, userId required 18 | * https://docs.aws.amazon.com/personalize/latest/dg/API_RS_GetRecommendations.html 19 | * @campaignArn a string: The Amazon Resource Name (ARN) of the solution version. 20 | * @itemId a string: The item ID to provide recommendations for. Required for RELATED_ITEMS recipe type. 21 | * @userId a string: The user ID to provide recommendations for. Required for USER_PERSONALIZATION recipe type. 22 | * @numResults an integer: The number of results to return. The default is 25. The maximum is 100. 23 | */ 24 | public any function getRecommendations( 25 | required string campaignArn, 26 | string itemId, 27 | string userId, 28 | numeric numResults 29 | ) { 30 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 31 | var args = { 'campaignArn': arguments.campaignArn }; 32 | if ( !isNull( arguments.itemId ) ) args[ 'itemId' ] = arguments.itemId; 33 | if ( !isNull( arguments.userId ) ) args[ 'userId' ] = arguments.userId; 34 | if ( !isNull( arguments.numResults ) ) args[ 'numResults' ] = arguments.numResults; 35 | 36 | return apiCall( 37 | requestSettings, 38 | 'GetRecommendations', 39 | '/recommendations', 40 | args 41 | ); 42 | } 43 | 44 | /** 45 | * Re-ranks a list of recommended items for the given user. The first item in the list is deemed the most likely item to be of interest to the user. 46 | Note 47 | The solution backing the campaign must have been created using a recipe of type PERSONALIZED_RANKING. 48 | * https://docs.aws.amazon.com/personalize/latest/dg/API_RS_GetPersonalizedRanking.html 49 | * @campaignArn a string: The Amazon Resource Name (ARN) of the solution version. 50 | * @itemList array of strings: A list of items (itemId's) to rank. If an item was not included in the training dataset, the item is appended to the end of the reranked list. 51 | * @userId a string: The user for which you want the campaign to provide a personalized ranking. 52 | */ 53 | public any function getPersonalizedRanking( 54 | required string campaignArn, 55 | array itemList, 56 | string userId 57 | ) { 58 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 59 | var args = { 'campaignArn': arguments.campaignArn, 'itemList': arguments.itemList, 'userId': arguments.userId }; 60 | 61 | return apiCall( 62 | requestSettings, 63 | 'GetPersonalizedRanking', 64 | '/personalize-ranking', 65 | args 66 | ); 67 | } 68 | 69 | private any function apiCall( 70 | required struct requestSettings, 71 | required string target, 72 | required string path, 73 | struct payload = { } 74 | ) { 75 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 76 | 77 | var payloadString = serializeJSON( payload ); 78 | var headers = { }; 79 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 80 | 81 | var apiResponse = api.call( 82 | 'personalize', 83 | host, 84 | requestSettings.region, 85 | 'POST', 86 | arguments.path, 87 | { }, 88 | headers, 89 | payloadString, 90 | requestSettings.awsCredentials 91 | ); 92 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 93 | 94 | return apiResponse; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /services/elastictranscoder.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'elastictranscoder'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /** 15 | * Gets a list of the pipelines associated with the current AWS account 16 | * http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/list-pipelines.html 17 | * @Ascending To list pipelines in chronological order by the date and time that they were submitted, enter true. To list pipelines in reverse chronological order, enter false. 18 | * @PageToken When Elastic Transcoder returns more than one page of results, use PageToken in subsequent GET requests to get each successive page of results. 19 | */ 20 | public any function listPipelines( 21 | boolean Ascending, 22 | string PageToken 23 | ) { 24 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 25 | var queryString = { }; 26 | if ( !isNull( arguments.Ascending ) ) queryString[ 'Ascending' ] = Ascending; 27 | if ( !isNull( arguments.PageToken ) ) queryString[ 'PageToken' ] = PageToken; 28 | var apiResponse = apiCall( 29 | requestSettings, 30 | 'GET', 31 | '/pipelines', 32 | queryString 33 | ); 34 | return apiResponse; 35 | } 36 | 37 | /** 38 | * Gets a list of all presets associated with the current AWS account 39 | * http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/list-presets.html 40 | * @Ascending To list presets in chronological order by the date and time that they were submitted, enter true. To list presets in reverse chronological order, enter false. 41 | * @PageToken When Elastic Transcoder returns more than one page of results, use PageToken in subsequent GET requests to get each successive page of results. 42 | */ 43 | public any function listPresets( 44 | boolean Ascending, 45 | string PageToken 46 | ) { 47 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 48 | var queryString = { }; 49 | if ( !isNull( arguments.Ascending ) ) queryString[ 'Ascending' ] = ( Ascending ? 'true' : 'false' ); 50 | if ( !isNull( arguments.PageToken ) ) queryString[ 'PageToken' ] = PageToken; 51 | return apiCall( 52 | requestSettings, 53 | 'GET', 54 | '/presets', 55 | queryString 56 | ); 57 | } 58 | 59 | /** 60 | * Creates a job 61 | * http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/create-job.html 62 | * @Job See http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/create-job.html for the correct job format 63 | */ 64 | public any function createJob( 65 | required struct Job 66 | ) { 67 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 68 | return apiCall( 69 | requestSettings, 70 | 'POST', 71 | '/jobs', 72 | { }, 73 | Job 74 | ); 75 | } 76 | 77 | private any function apiCall( 78 | required struct requestSettings, 79 | required string httpMethod, 80 | required string path, 81 | struct queryString = { }, 82 | struct payload = { } 83 | ) { 84 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 85 | 86 | var payloadString = payload.isEmpty() ? '' : serializeJSON( payload ); 87 | 88 | var headers = { }; 89 | if ( !payload.isEmpty() ) headers[ 'Content-Type' ] = 'application/x-amz-json-1.0'; 90 | 91 | var apiResponse = api.call( 92 | variables.service, 93 | host, 94 | requestSettings.region, 95 | httpMethod, 96 | '/' & variables.apiVersion & path, 97 | queryString, 98 | headers, 99 | payloadString, 100 | requestSettings.awsCredentials 101 | ); 102 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 103 | 104 | return apiResponse; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /services/ses.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'ses'; 4 | variables.endpoint = 'email'; 5 | 6 | public any function init( 7 | required any api, 8 | required struct settings 9 | ) { 10 | variables.api = arguments.api; 11 | variables.utils = variables.api.getUtils(); 12 | variables.apiVersion = arguments.settings.apiVersion; 13 | return this; 14 | } 15 | 16 | 17 | /** 18 | * Sends a email via Amazon SES 19 | * https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_SendEmail.html 20 | * @Content An object that contains the body of the message. You can send either a Simple message Raw message or a template Message. 21 | * @ConfigurationSetName The name of the configuration set to use when sending the email. 22 | * @Destination An object that contains the recipients of the email message. 23 | * @EmailTags A list of tags, in the form of name/value pairs, to apply to an email that you send using the SendEmail operation. Tags correspond to characteristics of the email that you define, so that you can publish email sending events. 24 | * @FeedbackForwardingEmailAddress The address that you want bounce and complaint notifications to be sent to. 25 | * @FeedbackForwardingEmailAddressIdentityArn This parameter is used only for sending authorization. It is the ARN of the identity that is associated with the sending authorization policy that permits you to use the email address specified in the FeedbackForwardingEmailAddress parameter. 26 | * @FromEmailAddress The email address to use as the "From" address for the email. The address that you specify has to be verified. 27 | * @FromEmailAddressIdentityArn This parameter is used only for sending authorization. It is the ARN of the identity that is associated with the sending authorization policy that permits you to use the email address specified in the FromEmailAddress parameter. 28 | * @ListManagementOptions An object used to specify a list or topic to which an email belongs, which will be used when a contact chooses to unsubscribe. 29 | * @ReplyToAddresses The "Reply-to" email addresses for the message. When the recipient replies to the message, each Reply-to address receives the reply. 30 | */ 31 | public any function sendEmail( 32 | required struct Content, 33 | string ConfigurationSetName, 34 | struct Destination, 35 | array EmailTags, 36 | string FeedbackForwardingEmailAddress, 37 | string FeedbackForwardingEmailAddressIdentityArn, 38 | string FromEmailAddress, 39 | string FromEmailAddressIdentityArn, 40 | struct ListManagementOptions, 41 | array ReplyToAddresses 42 | ) { 43 | var formParams = { }; 44 | for ( 45 | var key in [ 46 | 'Content', 47 | 'ConfigurationSetName', 48 | 'Destination', 49 | 'EmailTags', 50 | 'FeedbackForwardingEmailAddress', 51 | 'FeedbackForwardingEmailAddressIdentityArn', 52 | 'FromEmailAddress', 53 | 'FromEmailAddressIdentityArn', 54 | 'ListManagementOptions', 55 | 'ReplyToAddresses' 56 | ] 57 | ) { 58 | if ( arguments.keyExists( key ) ) { 59 | formParams[ key ] = arguments[ key ]; 60 | } 61 | } 62 | 63 | var requestSettings = api.resolveRequestSettings(); 64 | var apiResponse = apiCall( 65 | requestSettings, 66 | 'POST', 67 | '/v2/email/outbound-emails', 68 | { }, 69 | { }, 70 | serializeJSON( formParams ) 71 | ); 72 | if ( apiResponse.statusCode == 200 ) { 73 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 74 | } 75 | return apiResponse; 76 | } 77 | 78 | 79 | // private 80 | 81 | private string function getHost( 82 | required string region 83 | ) { 84 | return variables.endpoint & '.' & region & '.amazonaws.com'; 85 | } 86 | 87 | private any function apiCall( 88 | required struct requestSettings, 89 | string httpMethod = 'GET', 90 | string path = '/', 91 | struct queryParams = { }, 92 | struct headers = { }, 93 | string payload = '' 94 | ) { 95 | var host = getHost( requestSettings.region ); 96 | if ( !structKeyExists( headers, 'Content-Type' ) ) { 97 | headers[ 'Content-Type' ] = 'application/json'; 98 | } 99 | return api.call( 100 | variables.service, 101 | host, 102 | requestSettings.region, 103 | httpMethod, 104 | path, 105 | queryParams, 106 | headers, 107 | payload, 108 | requestSettings.awsCredentials 109 | ); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /com/utils.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | public any function init() { 4 | return this; 5 | } 6 | 7 | public any function getSystemSetting( 8 | required string key, 9 | any defaultValue 10 | ) { 11 | var system = createObject( 'java', 'java.lang.System' ); 12 | if ( !isNull( system.getenv( key ) ) ) return system.getenv( key ); 13 | if ( !isNull( system.getProperty( key ) ) ) return system.getProperty( key ); 14 | if ( !isNull( arguments.defaultValue ) ) return defaultValue; 15 | } 16 | 17 | public any function parseXmlDocument( 18 | required string xmlDocument 19 | ) { 20 | return parseXmlNode( xmlParse( xmlDocument ).xmlRoot ); 21 | } 22 | 23 | public any function parseXmlElement( 24 | required string xmlDocument, 25 | required string elementName 26 | ) { 27 | var result = [ ]; 28 | var elementNodes = xmlSearch( xmlParse( xmlDocument ), '//*[ local-name() = ''#elementName#'' ]' ); 29 | for ( var thisNode in elementNodes ) { 30 | result.append( parseXmlNode( thisNode ) ); 31 | } 32 | return result.len() ? ( result.len() > 1 ? result : result[ 1 ] ) : ''; 33 | } 34 | 35 | public any function parseXmlNode( 36 | required xml xmlNode 37 | ) { 38 | var result = { }; 39 | 40 | for ( var key in structKeyArray( xmlNode.xmlAttributes ) ) { 41 | result[ key ] = xmlNode.xmlAttributes[ key ]; 42 | } 43 | 44 | for ( var thisChild in xmlNode.xmlChildren ) { 45 | var xmlText = thisChild.xmlText.trim(); 46 | var thisValue = ( len( xmlText ) || !thisChild.xmlChildren.len() ) ? xmlText : parseXmlNode( thisChild ); 47 | if ( !result.keyExists( thisChild.XmlName ) ) { 48 | result[ thisChild.XmlName ] = thisValue; 49 | } else { 50 | if ( !isArray( result[ thisChild.XmlName ] ) ) 51 | result[ thisChild.XmlName ] = [ result[ thisChild.XmlName ] ]; 52 | result[ thisChild.XmlName ].append( thisValue ); 53 | } 54 | } 55 | 56 | var resultKeys = result.keyArray(); 57 | if ( resultKeys.len() == 1 && isArray( result[ resultKeys[ 1 ] ] ) ) return result[ resultKeys[ 1 ] ]; 58 | return result; 59 | } 60 | 61 | public string function parseKey( 62 | required string paramKey 63 | ) { 64 | var key = [ ]; 65 | for ( var character in paramKey.listToArray( '' ) ) { 66 | if ( arrayLen( key ) && asc( character ) != asc( lCase( character ) ) ) key.append( '-' ); 67 | key.append( lCase( character ) ); 68 | } 69 | return key.toList( '' ); 70 | } 71 | 72 | public array function parseHeaders( 73 | required struct headers 74 | ) { 75 | var sortedKeyArray = arguments.headers.keyArray(); 76 | sortedKeyArray.sort( 'textnocase' ); 77 | var processedHeaders = sortedKeyArray.map( function( key ) { 78 | return { name: key.lcase(), value: trim( headers[ key ] ) }; 79 | } ); 80 | return processedHeaders; 81 | } 82 | 83 | public string function parseQueryParams( 84 | required struct queryParams, 85 | boolean encodeQueryParams = true, 86 | boolean includeEmptyValues = true 87 | ) { 88 | var sortedKeyArray = queryParams.keyArray(); 89 | sortedKeyArray.sort( 'text' ); 90 | var queryString = arrayReduce( 91 | sortedKeyArray, 92 | function( queryString, queryParamKey ) { 93 | var encodedKey = encodeQueryParams ? encodeUrl( queryParamKey ) : queryParamKey; 94 | var encodedValue = encodeQueryParams && len( queryParams[ queryParamKey ] ) ? encodeUrl( 95 | queryParams[ queryParamKey ] 96 | ) : queryParams[ queryParamKey ]; 97 | return queryString.listAppend( 98 | encodedKey & ( includeEmptyValues || len( encodedValue ) ? ( '=' & encodedValue ) : '' ), 99 | '&' 100 | ); 101 | }, 102 | '' 103 | ); 104 | return queryString; 105 | } 106 | 107 | public string function encodeUrl( 108 | required string str, 109 | boolean encodeSlash = true 110 | ) { 111 | var result = replaceList( encodeForURL( arguments.str ), '%2D,%2E,%5F,%7E,+,*', '-,.,_,~,%20,%2A' ); 112 | if ( !encodeSlash ) result = replace( result, '%2F', '/', 'all' ); 113 | return result; 114 | } 115 | 116 | public string function iso8601( 117 | date dateToFormat = now() 118 | ) { 119 | return dateTimeFormat( dateToFormat, 'yyyymmdd', 'UTC' ) & 'T' & dateTimeFormat( dateToFormat, 'HHnnss', 'UTC' ) & 'Z'; 120 | } 121 | 122 | public string function iso8601Full( 123 | date dateToFormat = now() 124 | ) { 125 | return dateTimeFormat( dateToFormat, 'yyyy-mm-dd', 'UTC' ) & 'T' & dateTimeFormat( 126 | dateToFormat, 127 | 'HH:nn:ss', 128 | 'UTC' 129 | ) & '.000Z'; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /services/polly.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'polly'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | variables.defaultLanguageCode = arguments.settings.defaultLanguageCode; 12 | variables.defaultEngine = arguments.settings.defaultEngine; 13 | 14 | return this; 15 | } 16 | 17 | /** 18 | * Returns the list of voices that are available for use when requesting speech synthesis 19 | * https://docs.aws.amazon.com/polly/latest/dg/API_DescribeVoices.html 20 | * @Engine Specifies the engine (standard or neural) used by Amazon Polly when processing input text for speech synthesis 21 | * @NextToken An opaque pagination token returned from the previous DescribeVoices operation 22 | * @IncludeAdditionalLanguageCodes Specifies the engine (standard or neural) used by Amazon Polly when processing input text for speech synthesis 23 | * @LanguageCode The language identification tag (ISO 639 code for the language name-ISO 3166 country code) for filtering the list of voices returned 24 | */ 25 | public any function describeVoices( 26 | string Engine = variables.defaultEngine, 27 | string NextToken = '', 28 | boolean IncludeAdditionalLanguageCodes = false, 29 | string LanguageCode = variables.defaultLanguageCode 30 | ) { 31 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 32 | var queryParams = { 33 | 'Engine': Engine, 34 | 'IncludeAdditionalLanguageCodes': IncludeAdditionalLanguageCodes, 35 | 'LanguageCode': LanguageCode 36 | }; 37 | 38 | if ( len( NextToken ) ) { 39 | queryParams[ 'NextToken' ] = NextToken; 40 | } 41 | 42 | var apiResponse = apiCall( 43 | requestSettings, 44 | 'GET', 45 | '/v1/voices', 46 | queryParams 47 | ); 48 | 49 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 50 | 51 | return apiResponse; 52 | } 53 | 54 | /** 55 | * Synthesizes UTF-8 input, plain text or SSML, to a stream of bytes. 56 | * https://docs.aws.amazon.com/polly/latest/dg/API_SynthesizeSpeech.html 57 | * @Text Input text to synthesize 58 | * @VoiceId Voice ID to use for the synthesis 59 | * @OutputFormat The format in which the returned output will be encoded 60 | * @Engine Specifies the engine (standard or neural) for Amazon Polly to use when processing input text for speech synthesis 61 | * @LanguageCode Optional language code for the Synthesize Speech request 62 | * @SampleRate The audio frequency specified in Hz 63 | * @TexType Specifies whether the input text is plain text or SSM 64 | * @LexiconNames List of one or more pronunciation lexicon names you want the service to apply during synthesis 65 | * @SpeechMarkTypes The type of speech marks returned for the input text 66 | */ 67 | public any function synthesizeSpeech( 68 | required string Text, 69 | required string VoiceId, 70 | string OutputFormat = 'mp3', 71 | string Engine = variables.defaultEngine, 72 | string LanguageCode = variables.defaultLanguageCode, 73 | string SampleRate = '', 74 | string TextType = '', 75 | array LexiconNames = [ ], 76 | array SpeechMarkTypes = [ ] 77 | ) { 78 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 79 | var payload = { 80 | 'Text': Text, 81 | 'VoiceId': VoiceId, 82 | 'Engine': Engine, 83 | 'LanguageCode': Languagecode, 84 | 'OutputFormat': OutputFormat 85 | }; 86 | 87 | if ( len( SampleRate ) ) { 88 | payload[ 'SampleRate' ] = SampleRate; 89 | } 90 | 91 | if ( len( TextType ) ) { 92 | payload[ 'TextType' ] = TextType; 93 | } 94 | 95 | if ( !arrayIsEmpty( LexiconNames ) ) { 96 | payload[ 'LexiconNames' ] = LexiconNames; 97 | } 98 | 99 | if ( !arrayIsEmpty( SpeechMarkTypes ) ) { 100 | payload[ 'SpeechMarkTypes' ] = SpeechMarkTypes; 101 | } 102 | 103 | var apiResponse = apiCall( 104 | requestSettings, 105 | 'POST', 106 | '/v1/speech', 107 | { }, 108 | { }, 109 | payload 110 | ); 111 | 112 | return apiResponse; 113 | } 114 | 115 | 116 | // private 117 | 118 | private string function getHost( 119 | required string region 120 | ) { 121 | return variables.service & '.' & arguments.region & '.amazonaws.com'; 122 | } 123 | 124 | private any function apiCall( 125 | required struct requestSettings, 126 | string httpMethod = 'GET', 127 | string path = '/', 128 | struct queryParams = { }, 129 | struct headers = { }, 130 | struct payload = { } 131 | ) { 132 | var host = getHost( requestSettings.region ); 133 | var payloadString = payload.isEmpty() ? '' : serializeJSON( payload ); 134 | 135 | if ( !payload.isEmpty() ) headers[ 'Content-Type' ] = 'application/json'; 136 | 137 | return api.call( 138 | variables.service, 139 | host, 140 | requestSettings.region, 141 | httpMethod, 142 | path, 143 | queryParams, 144 | headers, 145 | payloadString, 146 | requestSettings.awsCredentials 147 | ); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /com/api.cfc: -------------------------------------------------------------------------------- 1 | component accessors="true" { 2 | 3 | property utils; 4 | property httpService; 5 | property credentials; 6 | property signer; 7 | property defaultRegion; 8 | 9 | public any function init( 10 | required string awsKey, 11 | required string awsSecretKey, 12 | required string defaultRegion, 13 | struct httpProxy = { server: '', port: 80 } 14 | ) { 15 | variables.utils = new utils(); 16 | variables.httpService = server.keyExists( 'lucee' ) ? new httpLucee( utils, httpProxy ) : new httpColdFusion( utils, httpProxy ); 17 | variables.credentials = new credentials( awsKey, awsSecretKey, this ); 18 | variables.signer = new signature_v4( this ); 19 | variables.defaultRegion = arguments.defaultRegion.len() ? arguments.defaultRegion : utils.getSystemSetting( 20 | 'AWS_DEFAULT_REGION', 21 | '' 22 | ); 23 | 24 | if ( !variables.defaultRegion.len() ) { 25 | var profile = utils.getSystemSetting( 'AWS_PROFILE', 'default' ); 26 | var userHome = utils.getSystemSetting( 'user.home' ).replace( '\', '/', 'all' ); 27 | var configFile = utils.getSystemSetting( 'AWS_CONFIG_FILE', userHome & '/.aws/config' ); 28 | var region = getProfileString( configFile, profile, 'region' ).trim(); 29 | variables.defaultRegion = region.len() ? region : 'us-east-1'; 30 | } 31 | 32 | return this; 33 | } 34 | 35 | public struct function resolveRequestSettings( 36 | struct awsCredentials = { }, 37 | string region = defaultRegion, 38 | string bucket = '' 39 | ) { 40 | if ( !awsCredentials.isEmpty() ) { 41 | awsCredentials = credentials.defaultCredentials( argumentCollection = awsCredentials ); 42 | } 43 | var settings = { awsCredentials: awsCredentials, region: region }; 44 | if ( len( arguments.bucket ) ) { 45 | settings.bucket = arguments.bucket; 46 | } 47 | return settings; 48 | } 49 | 50 | public any function call( 51 | required string service, 52 | required string host, 53 | string region = defaultRegion, 54 | string httpMethod = 'GET', 55 | string path = '/', 56 | struct queryParams = { }, 57 | struct headers = { }, 58 | any body = '', 59 | struct awsCredentials = { }, 60 | boolean encodeurl = true, 61 | boolean useSSL = true, 62 | numeric timeout = 0 63 | ) { 64 | if ( awsCredentials.isEmpty() ) { 65 | awsCredentials = credentials.getCredentials(); 66 | } 67 | 68 | var encodedPath = utils.encodeUrl( path, false ); 69 | if ( encodeurl ) path = encodedPath; 70 | 71 | var signedRequestHeaders = signer.getHeadersWithAuthorization( 72 | service, 73 | host, 74 | region, 75 | httpMethod, 76 | path, 77 | queryParams, 78 | headers, 79 | body, 80 | awsCredentials 81 | ); 82 | 83 | var httpArgs = { }; 84 | httpArgs[ 'httpMethod' ] = httpMethod; 85 | httpArgs[ 'path' ] = host & encodedPath; 86 | httpArgs[ 'headers' ] = signedRequestHeaders; 87 | httpArgs[ 'queryParams' ] = queryParams; 88 | httpArgs[ 'useSSL' ] = useSSL; 89 | if ( !isNull( arguments.body ) ) httpArgs[ 'body' ] = body; 90 | if ( timeout ) httpArgs[ 'timeout' ] = timeout; 91 | // writeDump( httpArgs ); 92 | 93 | var requestStart = getTickCount(); 94 | var rawResponse = httpService.makeHttpRequest( argumentCollection = httpArgs ); 95 | // writeDump( rawResponse ); 96 | 97 | var apiResponse = { }; 98 | apiResponse[ 'responseTime' ] = getTickCount() - requestStart; 99 | apiResponse[ 'responseHeaders' ] = rawResponse.responseheader; 100 | apiResponse[ 'statusCode' ] = listFirst( rawResponse.statuscode, ' ' ); 101 | apiResponse[ 'rawData' ] = rawResponse.filecontent; 102 | 103 | if ( 104 | find('application/x-amz-json', rawResponse.mimetype) && 105 | !isSimpleValue( apiResponse.rawData ) 106 | ) { 107 | apiResponse.rawData = apiResponse.rawData.toString( 'utf-8' ); 108 | } 109 | 110 | apiResponse[ 'host' ] = arguments.host; 111 | 112 | if ( apiResponse.statusCode != 200 && isXML( apiResponse.rawData ) ) { 113 | apiResponse[ 'error' ] = utils.parseXmlDocument( apiResponse.rawData ); 114 | } 115 | 116 | return apiResponse; 117 | } 118 | 119 | public any function signedUrl( 120 | required string service, 121 | required string host, 122 | string region = defaultRegion, 123 | string httpMethod = 'GET', 124 | string path = '/', 125 | struct queryParams = { }, 126 | numeric expires = 300, 127 | struct awsCredentials = { }, 128 | boolean encodeurl = true 129 | ) { 130 | if ( awsCredentials.isEmpty() ) { 131 | awsCredentials = credentials.getCredentials(); 132 | } 133 | 134 | var encodedPath = utils.encodeUrl( path, false ); 135 | if ( encodeurl ) path = encodedPath; 136 | 137 | var signedQueryParams = signer.getQueryParamsWithAuthorization( 138 | service, 139 | host, 140 | region, 141 | httpMethod, 142 | path, 143 | queryParams, 144 | expires, 145 | awsCredentials 146 | ); 147 | 148 | return host & encodedPath & '?' & utils.parseQueryParams( signedQueryParams ); 149 | } 150 | 151 | public any function authorizationParams( 152 | required string service, 153 | string region = defaultRegion, 154 | string isoTime = '', 155 | struct awsCredentials = { } 156 | ) { 157 | if ( awsCredentials.isEmpty() ) { 158 | awsCredentials = credentials.getCredentials(); 159 | } 160 | 161 | return signer.getAuthorizationParams( 162 | service, 163 | region, 164 | isoTime, 165 | awsCredentials 166 | ); 167 | } 168 | 169 | public any function sign( 170 | required struct awsCredentials, 171 | required string isoDateShort, 172 | required string region, 173 | required string service, 174 | required string stringToSign 175 | ) { 176 | if ( awsCredentials.isEmpty() ) { 177 | awsCredentials = credentials.getCredentials(); 178 | } 179 | return signer.sign( argumentCollection = arguments ); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /services/autoscaling.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'autoscaling'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.utils = variables.api.getUtils(); 11 | variables.apiVersion = arguments.settings.apiVersion; 12 | return this; 13 | } 14 | 15 | /** 16 | * Sets the size of the specified Auto Scaling group. 17 | * https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_SetDesiredCapacity.html 18 | * @AutoScalingGroupName The name of the Auto Scaling group. 19 | * @DesiredCapacity The desired capacity is the initial capacity of the Auto Scaling group after this operation completes and the capacity it attempts to maintain. 20 | * @HonorCooldown Indicates whether Amazon EC2 Auto Scaling waits for the cooldown period to complete before initiating a scaling activity to set your Auto Scaling group to its new capacity. By default, Amazon EC2 Auto Scaling does not honor the cooldown period during manual scaling activities. 21 | */ 22 | public any function SetDesiredCapacity( 23 | string AutoScalingGroupName = '', 24 | numeric DesiredCapacity = 1, 25 | boolean HonorCooldown = false 26 | ) { 27 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 28 | var queryParams = { 'Action': 'SetDesiredCapacity' }; 29 | 30 | queryParams[ 'HonorCooldown' ] = arguments.HonorCooldown; 31 | queryParams[ 'AutoScalingGroupName' ] = arguments.AutoScalingGroupName; 32 | queryParams[ 'DesiredCapacity' ] = arguments.DesiredCapacity; 33 | 34 | var apiResponse = apiCall( 35 | requestSettings, 36 | 'GET', 37 | '/', 38 | queryParams 39 | ); 40 | if ( apiResponse.statusCode == 200 ) { 41 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 42 | } 43 | return apiResponse; 44 | } 45 | 46 | /** 47 | * Gets information about the Auto Scaling instances in the account and Region. 48 | * https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingInstances.html 49 | * @InstanceIds The IDs of the instances one wishes to describe 50 | * @MaxRecords The maximum number of items to return with this call. The default value is 50 and the maximum value is 50. 51 | * @NextToken The token for the next set of items to return. (You received this token from a previous call.) 52 | */ 53 | public any function DescribeAutoScalingInstances( 54 | required array InstanceIds = [ ], 55 | numeric MaxRecords = 50, 56 | string NextToken = '' 57 | ) { 58 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 59 | var queryParams = { 'Action': 'DescribeAutoScalingInstances' }; 60 | 61 | queryParams[ 'MaxRecords' ] = arguments.MaxRecords; 62 | 63 | if ( len( arguments.NextToken ) ) queryParams[ 'NextToken' ] = arguments.NextToken; 64 | 65 | parseIds( arguments.InstanceIds, queryParams ); 66 | 67 | var apiResponse = apiCall( 68 | requestSettings, 69 | 'GET', 70 | '/', 71 | queryParams 72 | ); 73 | if ( apiResponse.statusCode == 200 ) { 74 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 75 | } 76 | return apiResponse; 77 | } 78 | 79 | /** 80 | * Gets information about the Auto Scaling groups in the account and Region. 81 | * https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html 82 | * @InstanceIds The IDs of the instances one wishes to describe 83 | * @MaxRecords The maximum number of items to return with this call. The default value is 50 and the maximum value is 50. 84 | * @NextToken The token for the next set of items to return. (You received this token from a previous call.) 85 | */ 86 | public any function DescribeAutoScalingGroups( 87 | required array AutoScalingGroupNames = [ ], 88 | array Filters = [ ], // no support yet 89 | numeric MaxRecords = 50, 90 | string NextToken = '' 91 | ) { 92 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 93 | var queryParams = { 'Action': 'DescribeAutoScalingGroups' }; 94 | 95 | queryParams[ 'MaxRecords' ] = arguments.MaxRecords; 96 | 97 | if ( len( arguments.NextToken ) ) queryParams[ 'NextToken' ] = arguments.NextToken; 98 | 99 | parseIds( arguments.AutoScalingGroupNames, queryParams, AutoScalingGroupNames.member ); 100 | 101 | var apiResponse = apiCall( 102 | requestSettings, 103 | 'GET', 104 | '/', 105 | queryParams 106 | ); 107 | if ( apiResponse.statusCode == 200 ) { 108 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 109 | } 110 | return apiResponse; 111 | } 112 | 113 | // private 114 | 115 | private string function getHost( 116 | required string region 117 | ) { 118 | return variables.service & '.' & region & '.amazonaws.com'; 119 | } 120 | 121 | private any function apiCall( 122 | required struct requestSettings, 123 | string httpMethod = 'GET', 124 | string path = '/', 125 | struct queryParams = { }, 126 | struct headers = { }, 127 | any payload = '' 128 | ) { 129 | var host = getHost( requestSettings.region ); 130 | 131 | if ( isStruct( payload ) ) { 132 | structAppend( payload, { 'Version': variables.apiVersion }, false ); 133 | structAppend( headers, { 'Content-Type': 'application/x-www-form-urlencoded' }, false ); 134 | payload = utils.parseQueryParams( payload ); 135 | } else { 136 | structAppend( queryParams, { 'Version': variables.apiVersion }, false ); 137 | } 138 | return api.call( 139 | variables.service, 140 | host, 141 | requestSettings.region, 142 | httpMethod, 143 | path, 144 | queryParams, 145 | headers, 146 | payload, 147 | requestSettings.awsCredentials 148 | ); 149 | } 150 | 151 | private void function parseIds( 152 | required array IDs = [ ], 153 | struct queryParams, 154 | string prefix = 'InstanceID' 155 | ) { 156 | if ( len( arguments.IDs ) ) { 157 | IDs.each( function( e, i ) { 158 | queryParams[ '#prefix#.#i#' ] = e; 159 | } ); 160 | } 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /services/kms.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'kms'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | variables.argumentTypes = getArgTypes(); 12 | variables.argumentKeys = variables.argumentTypes.keyArray(); 13 | variables.platform = server.keyExists( 'lucee' ) ? 'Lucee' : 'ColdFusion'; 14 | return this; 15 | } 16 | 17 | /** 18 | * Returns a struct including the ciphertext blob representing the encrypted value 19 | * https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html 20 | * @KeyId The AWS ID for the CMK Key, either the ID, the ARN, or an alias. 21 | * @Plaintext The data to be encrypted. 22 | * @EncryptionContext A struct of values used to validate during decryption. The values set during encryption must be the same during decryption. 23 | * @GrantTokens An array of strings corresponding to AWS grant tokens. 24 | */ 25 | public any function encrypt( 26 | required string KeyId, 27 | required string Plaintext, 28 | struct EncryptionContext = { }, 29 | array GrantTokens = [ ] 30 | ) { 31 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 32 | var payload = buildPayload( arguments ); 33 | // Base64 encode the value before sending 34 | payload[ 'Plaintext' ] = toBase64( payload[ 'Plaintext' ] ); 35 | 36 | return apiCall( requestSettings, 'Encrypt', payload ); 37 | } 38 | 39 | /** 40 | * Returns a struct including the plaintext value representing the decrypted value (may be Base64 encoded) 41 | * https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html 42 | * @CiphertextBlob The data to be encrypted. 43 | * @EncryptionContext A struct of values used to validate during decryption. The values set during encryption must be the same during decryption. 44 | * @GrantTokens An array of strings corresponding to AWS grant tokens. 45 | */ 46 | public any function decrypt( 47 | required string CiphertextBlob, 48 | struct EncryptionContext = { }, 49 | array GrantTokens = [ ] 50 | ) { 51 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 52 | var payload = buildPayload( arguments ); 53 | var response = apiCall( requestSettings, 'Decrypt', payload ); 54 | 55 | // decode the Base64 encoded plaintext value, if encoded; else return the pure response 56 | try { 57 | response.data[ 'Plaintext' ] = toString( toBinary( response.data[ 'Plaintext' ] ) ); 58 | return response; 59 | } catch ( any e ) { 60 | return response; 61 | } 62 | } 63 | 64 | /** 65 | * Returns a struct including the ciphertext blob representing the re-encrypted value 66 | * https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html 67 | * @CiphertextBlob The data to be re-encrypted. 68 | * @DestinationKeyId The AWS ID for the CMK Key to re-encrypt using, either the ID, the ARN, or an alias. 69 | * @DestinationEncryptionContext A struct of values used to validate during decryption. The values set during encryption must be the same during decryption. This is the context to be used AFTER the value has been re-encrypted. 70 | * @SourceEncryptionContext A struct of values used to validate during decryption. The values set during encryption must be the same during decryption. This is the context that was used when the value was first encrypted using the "old" key. 71 | * @GrantTokens An array of strings corresponding to AWS grant tokens. 72 | */ 73 | public any function reEncrypt( 74 | required string CiphertextBlob, 75 | required string DestinationKeyId, 76 | struct DestinationEncryptionContext = { }, 77 | struct SourceEncryptionContext = { }, 78 | array GrantTokens = [ ] 79 | ) { 80 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 81 | var payload = buildPayload( arguments ); 82 | return apiCall( requestSettings, 'ReEncrypt', payload ); 83 | } 84 | 85 | // private methods 86 | 87 | private any function apiCall( 88 | required struct requestSettings, 89 | required string target, 90 | struct payload = { } 91 | ) { 92 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 93 | var payloadString = serializeJSON( payload ); 94 | 95 | var headers = { }; 96 | headers[ 'X-Amz-Target' ] = 'TrentService.' & arguments.target; 97 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 98 | 99 | var apiResponse = api.call( 100 | variables.service, 101 | host, 102 | requestSettings.region, 103 | 'POST', 104 | '/', 105 | { }, 106 | headers, 107 | payloadString, 108 | requestSettings.awsCredentials 109 | ); 110 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 111 | 112 | return apiResponse; 113 | } 114 | 115 | private any function buildPayload( 116 | required any args 117 | ) { 118 | var payload = { }; 119 | for ( var key in args ) { 120 | var keyIndex = variables.argumentKeys.findNoCase( key ); 121 | if ( !keyIndex ) continue; 122 | var argType = variables.argumentTypes[ key ]; 123 | var casedKey = variables.argumentKeys[ keyIndex ]; 124 | switch ( argType ) { 125 | case 'array': 126 | case 'string': 127 | if ( args[ key ].len() ) payload[ casedKey ] = args[ key ]; 128 | break; 129 | case 'boolean': 130 | case 'numeric': 131 | if ( args[ key ] ) payload[ casedKey ] = args[ key ]; 132 | break; 133 | case 'struct': 134 | if ( !args[ key ].isEmpty() ) payload[ casedKey ] = args[ key ]; 135 | break; 136 | } 137 | } 138 | return payload; 139 | } 140 | 141 | private struct function getArgTypes() { 142 | var metadata = getMetadata( this ); 143 | var typed = [ ]; 144 | var result = { }; 145 | 146 | for ( var funct in metadata.functions ) { 147 | if ( arrayFindNoCase( [ 'init' ], funct.name ) || funct.access != 'public' ) continue; 148 | for ( var param in funct.parameters ) { 149 | result[ param.name ] = typed.findNoCase( param.name ) ? 'typed' : param.type; 150 | } 151 | } 152 | 153 | return result; 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /com/signature_v4.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | public any function init( 4 | required any api 5 | ) { 6 | variables.utils = api.getUtils(); 7 | variables.lf = chr( 10 ); 8 | return this; 9 | } 10 | 11 | public struct function getHeadersWithAuthorization( 12 | required string service, 13 | required string host, 14 | required string region, 15 | required string httpMethod, 16 | required string path, 17 | required struct queryParams, 18 | required struct headers, 19 | required any payload, 20 | required struct awsCredentials 21 | ) { 22 | var isoTime = utils.iso8601(); 23 | var requestHeaders = { 'X-Amz-Date': isoTime, 'Host': host }; 24 | 25 | if ( len( awsCredentials.token ) ) { 26 | requestHeaders[ 'X-Amz-Security-Token' ] = awsCredentials.token; 27 | } 28 | requestHeaders.append( headers ); 29 | 30 | var canonicalRequest = createCanonicalRequest( 31 | httpMethod, 32 | path, 33 | queryParams, 34 | requestHeaders, 35 | payload 36 | ); 37 | var stringToSign = createStringToSign( 38 | region, 39 | service, 40 | isoTime, 41 | canonicalRequest 42 | ); 43 | var credentialScope = stringToSign.listGetAt( stringToSign.listLen( lf ) - 1, lf ); 44 | var signedHeaders = canonicalRequest.listGetAt( canonicalRequest.listLen( lf ) - 1, lf ); 45 | var signature = sign( 46 | awsCredentials, 47 | isoTime.left( 8 ), 48 | region, 49 | service, 50 | stringToSign 51 | ); 52 | 53 | var authorization = 'AWS4-HMAC-SHA256 '; 54 | authorization &= 'Credential=' & awsCredentials.awsKey & '/' & credentialScope & ', '; 55 | authorization &= 'SignedHeaders=' & signedHeaders & ', '; 56 | authorization &= 'Signature=' & signature; 57 | 58 | requestHeaders[ 'Authorization' ] = authorization; 59 | return requestHeaders; 60 | } 61 | 62 | public struct function getQueryParamsWithAuthorization( 63 | required string service, 64 | required string host, 65 | required string region, 66 | required string httpMethod, 67 | required string path, 68 | required struct queryParams, 69 | required numeric expires, 70 | required struct awsCredentials 71 | ) { 72 | var isoTime = utils.iso8601(); 73 | var params = { }; 74 | params.append( queryParams ); 75 | params.append( 76 | getAuthorizationParams( 77 | service, 78 | region, 79 | isoTime, 80 | awsCredentials 81 | ) 82 | ); 83 | params[ 'X-Amz-SignedHeaders' ] = 'host'; 84 | params[ 'X-Amz-Expires' ] = expires; 85 | 86 | var canonicalRequest = createCanonicalRequest( 87 | httpMethod, 88 | path, 89 | params, 90 | { 'Host': host }, 91 | '', 92 | true 93 | ); 94 | var stringToSign = createStringToSign( 95 | region, 96 | service, 97 | isoTime, 98 | canonicalRequest 99 | ); 100 | // writeDump( canonicalRequest ); 101 | // writeDump( stringToSign ); 102 | params[ 'X-Amz-Signature' ] = sign( 103 | awsCredentials, 104 | isoTime.left( 8 ), 105 | region, 106 | service, 107 | stringToSign 108 | ); 109 | return params; 110 | } 111 | 112 | public struct function getAuthorizationParams( 113 | required string service, 114 | required string region, 115 | required string isoTime, 116 | required struct awsCredentials 117 | ) { 118 | var params = { 119 | 'X-Amz-Algorithm': 'AWS4-HMAC-SHA256', 120 | 'X-Amz-Credential': awsCredentials.awsKey & '/' & isoTime.left( 8 ) & '/' & region & '/' & service & '/aws4_request', 121 | 'X-Amz-Date': isoTime 122 | }; 123 | 124 | if ( len( awsCredentials.token ) ) { 125 | params[ 'X-Amz-Security-Token' ] = awsCredentials.token; 126 | } 127 | 128 | return params; 129 | } 130 | 131 | public string function createCanonicalRequest( 132 | required string httpMethod, 133 | required string path, 134 | required struct queryParams, 135 | required struct headers, 136 | required any payload, 137 | boolean unsignedPayload = false 138 | ) { 139 | var result = [ ]; 140 | result.append( httpMethod ); 141 | result.append( utils.encodeUrl( path, false ) ); 142 | result.append( utils.parseQueryParams( queryParams ) ); 143 | 144 | var headersParsed = utils.parseHeaders( headers ); 145 | for ( var header in headersParsed ) { 146 | result.append( header.name & ':' & header.value ); 147 | } 148 | 149 | result.append( '' ); 150 | result.append( 151 | headersParsed 152 | .map( function( header ) { 153 | return header.name; 154 | } ) 155 | .toList( ';' ) 156 | ); 157 | if ( unsignedPayload ) { 158 | result.append( 'UNSIGNED-PAYLOAD' ); 159 | } else { 160 | result.append( hash( payload, 'SHA-256' ).lcase() ); 161 | } 162 | return result.toList( lf ); 163 | } 164 | 165 | public string function createStringToSign( 166 | required string region, 167 | required string service, 168 | required string isoTime, 169 | required string canonicalRequest 170 | ) { 171 | var result = [ ]; 172 | result.append( 'AWS4-HMAC-SHA256' ); 173 | result.append( isoTime ); 174 | result.append( isoTime.left( 8 ) & '/' & region & '/' & service & '/aws4_request' ); 175 | result.append( hash( canonicalRequest, 'SHA-256' ).lcase() ); 176 | return result.toList( lf ); 177 | } 178 | 179 | public string function sign( 180 | required struct awsCredentials, 181 | required string isoDateShort, 182 | required string region, 183 | required string service, 184 | required string stringToSign 185 | ) { 186 | var signingKey = binaryDecode( 187 | hmac( 188 | isoDateShort, 189 | 'AWS4' & awsCredentials.awsSecretKey, 190 | 'hmacSHA256', 191 | 'utf-8' 192 | ), 193 | 'hex' 194 | ); 195 | signingKey = binaryDecode( 196 | hmac( 197 | region, 198 | signingKey, 199 | 'hmacSHA256', 200 | 'utf-8' 201 | ), 202 | 'hex' 203 | ); 204 | signingKey = binaryDecode( 205 | hmac( 206 | service, 207 | signingKey, 208 | 'hmacSHA256', 209 | 'utf-8' 210 | ), 211 | 'hex' 212 | ); 213 | signingKey = binaryDecode( 214 | hmac( 215 | 'aws4_request', 216 | signingKey, 217 | 'hmacSHA256', 218 | 'utf-8' 219 | ), 220 | 'hex' 221 | ); 222 | return hmac( 223 | stringToSign, 224 | signingKey, 225 | 'hmacSHA256', 226 | 'utf-8' 227 | ).lcase(); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /services/rekognition.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'rekognition'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | 15 | /** 16 | * Detects faces within an image that is provided as input. 17 | * https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectFaces.html 18 | * @Image a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 19 | * @Attributes Optional. An array of facial attributes to be returned. Alternately, specify "DEFAULT" to include the default set of attributes, or "ALL" to include all attributes. 20 | */ 21 | public any function detectFaces( 22 | required struct Image, 23 | array Attributes 24 | ) { 25 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 26 | var args = { 'Image': arguments.Image }; 27 | if ( !isNull( arguments.Attributes ) ) args[ 'Attributes' ] = arguments.Attributes; 28 | 29 | return apiCall( requestSettings, 'DetectFaces', args ); 30 | } 31 | 32 | /** 33 | * Detects instances of real-world entities within an image (JPEG or PNG) provided as input. This includes objects like flower, tree, and table; events like wedding, graduation, and birthday party; and concepts like landscape, evening, and nature. 34 | * https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectLabels.html 35 | * @Image a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 36 | * @MaxLabels Optional numeric. Maximum number of labels you want the service to return in the response. The service returns the specified number of highest confidence labels. 37 | */ 38 | public any function detectLabels( 39 | required struct Image, 40 | numeric MaxLabels 41 | ) { 42 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 43 | var args = { 'Image': arguments.Image }; 44 | if ( !isNull( arguments.MaxLabels ) ) args[ 'MaxLabels' ] = arguments.MaxLabels; 45 | 46 | return apiCall( requestSettings, 'DetectLabels', args ); 47 | } 48 | 49 | /** 50 | * Detects explicit or suggestive adult content in a specified JPEG or PNG format image. 51 | * https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectModerationLabels.html 52 | * @Image a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 53 | * @MinConfidence Optional. Specifies the minimum confidence level for the labels to return. Amazon Rekognition doesn't return any labels with a confidence level lower than this specified value. Valid Values are 0 - 100. Default when argument is not provided is 50. 54 | */ 55 | public any function detectModerationLabels( 56 | required struct Image, 57 | numeric MinConfidence 58 | ) { 59 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 60 | var args = { 'Image': arguments.Image }; 61 | if ( !isNull( arguments.MinConfidence ) ) args[ 'MinConfidence' ] = arguments.MinConfidence; 62 | 63 | return apiCall( requestSettings, 'DetectModerationLabels', args ); 64 | } 65 | 66 | /** 67 | * Detects text in the input image and converts it into machine-readable text. 68 | * https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectText.html 69 | * @Image a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 70 | */ 71 | public any function detectText( 72 | required struct Image 73 | ) { 74 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 75 | return apiCall( requestSettings, 'DetectText', { 'Image': arguments.Image } ); 76 | } 77 | 78 | /** 79 | * Returns an array of celebrities recognized in the input image. 80 | * https://docs.aws.amazon.com/rekognition/latest/dg/API_RecognizeCelebrities.html 81 | * @Image a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 82 | */ 83 | public any function recognizeCelebrities( 84 | required struct Image 85 | ) { 86 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 87 | return apiCall( requestSettings, 'RecognizeCelebrities', { 'Image': arguments.Image } ); 88 | } 89 | 90 | /** 91 | * Returns an array of face matches ordered by similarity score in descending order 92 | * https://docs.aws.amazon.com/rekognition/latest/dg/API_CompareFaces.html 93 | * @SourceImage a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 94 | * @TargetImage a struct with a "Bytes" key containing Base64-encoded binary data or an "S3Object" struct containing a "Bucket", "Name", and optional "Version" - https://docs.aws.amazon.com/rekognition/latest/APIReference/API_Image.html 95 | * @SimilarityThreshold a numeric minimum level of confidence that a match must meet to be included. Valid Range: Minimum value of 0. Maximum value of 100. 96 | * @QualityFilter a string filter that specifies a quality bar for how much filtering is done to identify faces. Valid Values: NONE | AUTO | LOW | MEDIUM | HIGH 97 | */ 98 | public any function compareFaces( 99 | required struct SourceImage, 100 | required struct TargetImage, 101 | numeric SimilarityThreshold, 102 | string QualityFilter 103 | ) { 104 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 105 | var args = { 'SourceImage': arguments.SourceImage, 'TargetImage': arguments.TargetImage }; 106 | if ( !isNull( arguments.SimilarityThreshold ) ) args[ 'SimilarityThreshold' ] = arguments.SimilarityThreshold; 107 | if ( !isNull( arguments.QualityFilter ) ) args[ 'QualityFilter' ] = arguments.QualityFilter; 108 | 109 | return apiCall( requestSettings, 'CompareFaces', args ); 110 | } 111 | 112 | private any function apiCall( 113 | required struct requestSettings, 114 | required string target, 115 | struct payload = { } 116 | ) { 117 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 118 | 119 | var payloadString = payload.isEmpty() ? '' : serializeJSON( payload ); 120 | var headers = { }; 121 | headers[ 'X-Amz-Target' ] = 'RekognitionService.#target#'; 122 | if ( !payload.isEmpty() ) headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 123 | 124 | var apiResponse = api.call( 125 | variables.service, 126 | host, 127 | requestSettings.region, 128 | 'POST', 129 | '/', 130 | { }, 131 | headers, 132 | payloadString, 133 | requestSettings.awsCredentials 134 | ); 135 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 136 | 137 | return apiResponse; 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aws-cfml 2 | 3 | **aws-cfml** is a CFML library for interacting with AWS APIs. 4 | 5 | **It requires Lucee 4.5+ or ColdFusion 11+.** 6 | 7 | It currently supports the following APIs: 8 | - cognitoIdentity 9 | - connect 10 | - dynamodb 11 | - ec2 12 | - ec2 auto-scaling groups 13 | - elasticsearch 14 | - elastictranscoder 15 | - polly 16 | - rekognition 17 | - s3 18 | - secretsmanager 19 | - ses 20 | - sns 21 | - ssm 22 | - sqs 23 | - translate 24 | 25 | _Note: It has full support for the AWS S3 and AWS DynamoDB REST APIs. Other services are supported to varying degrees - if you are using a service and add a method you need, please consider contributing it back to this project. My thanks to [@davidsf](https://github.com/davidsf) and [@sjdaniels](https://github.com/sjdaniels) who contributed the translate and rekognition service components respectively._ 26 | 27 | **aws-cfml** also supports making signed requests to arbitrary AWS endpoints. It currently supports only AWS Signature v4 for authentication. 28 | 29 | ## Installation 30 | This wrapper can be installed as standalone library or as a ColdBox Module. Either approach requires a simple CommandBox command: 31 | 32 | ``` 33 | $ box install aws-cfml 34 | ``` 35 | 36 | Alternatively the git repository can be cloned into the desired directory. 37 | 38 | ### Standalone Usage 39 | 40 | Once the library has been installed, the core `aws` component can be instantiated directly: 41 | 42 | ```cfc 43 | aws = new path.to.awscfml.aws( 44 | awsKey = 'YOUR_PUBLIC_KEY', 45 | awsSecretKey = 'YOUR_PRIVATE_KEY', 46 | defaultRegion = 'us-east-1' 47 | ); 48 | ``` 49 | 50 | *Note: An optional `httpProxy` argument is available when initializing the core `aws` component (a struct with `server` and `port` keys). When set this will proxy all AWS requests.* 51 | 52 | ### ColdBox Module 53 | 54 | To use the library as a ColdBox Module, add the init arguments to the `moduleSettings` struct in `config/Coldbox.cfc`: 55 | 56 | ```cfc 57 | moduleSettings = { 58 | awscfml: { 59 | awsKey: '', 60 | awsSecretKey: '', 61 | defaultRegion: '' 62 | } 63 | } 64 | ``` 65 | 66 | You can then leverage the library via the injection DSL: `aws@awscfml`: 67 | 68 | ```cfc 69 | property name="aws" inject="aws@awscfml"; 70 | ``` 71 | 72 | *Note: You can bypass the init arguments altogether and use environment variables, a credentials file, or an IAM role with aws-cfml. See [Credentials](#credentials) below.* 73 | 74 | ## Getting Started 75 | 76 | ```cfc 77 | // aws.cfc contains components for interacting with AWS services 78 | aws = new aws(awsKey = 'YOUR_PUBLIC_KEY', awsSecretKey = 'YOUR_PRIVATE_KEY', defaultRegion = 'us-east-1'); 79 | 80 | buckets = aws.s3.listBuckets(); 81 | tables = aws.dynamodb.listTables(); 82 | 83 | // you can make signed requests to any AWS endpoint using the following: 84 | response = aws.api.call(service, host, region, httpMethod, path, queryParams, headers, body, awsCredentials); 85 | 86 | // using named arguments you can supply a `region` to any method call 87 | // this overrides the default region set at init 88 | response = aws.s3.listBucket(region = 'us-west-1', bucket = 'mybucket'); 89 | ``` 90 | 91 | All responses are returned as a struct with the following format: 92 | 93 | ```cfc 94 | response = { 95 | responseHeaders: { } // struct containing the headers returned from the HTTP request 96 | responseTime: 123 // time in milliseconds of the HTTP request 97 | statusCode: 200 // status code returned 98 | rawData: bodyOfHTTPResponse // whatever was in the body of the HTTP request response 99 | data: parsedRawData // the rawData response parsed into CFML (from XML or JSON) 100 | }; 101 | ``` 102 | 103 | _Note:_ The `data` key might not be present if the request is one where it does not make sense to parse the body of the response. (For instance when getting an object from S3.) 104 | 105 | ## Credentials 106 | 107 | You can supply an aws key and secret key at initialization: 108 | 109 | ```cfc 110 | aws = new aws( awsKey = 'YOUR_PUBLIC_KEY', awsSecretKey = 'YOUR_PRIVATE_KEY' ) 111 | ``` 112 | 113 | If you do not then `aws-cfml` will follow the configuration resolution followed by the AWS CLI: - see *Configuration Settings and Precedence*. In order, it will check for the presence of environment variables, a credentials file, and IAM role credentials (which are only valid on EC2). 114 | 115 | You can also pass credentials as a named argument to any service method: 116 | 117 | ```cfc 118 | aws = new aws(); 119 | awsCredentials = {awsKey: 'ANOTHER_PUBLIC_KEY', awsSecretKey: 'ANOTHER_PRIVATE_KEY'}; 120 | response = aws.s3.listBucket(awsCredentials = awsCredentials, region = 'us-west-1', bucket = 'mybucket'); 121 | ``` 122 | 123 | ### DynamoDB 124 | 125 | DynamoDB data is typed. The types supported are `Number`, `String`, `Binary`, `Boolean`, `Null`, `String Set`, `Number Set`, `Binary Set`, `List` and `Map`. 126 | http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModel.DataTypes 127 | 128 | This library's DynamoDB implementation is set up to work with CFML types by default, so that you can supply data in a struct containing string, number, boolean, binary, null, array and struct values. Structs and arrays can be nested. Everything is then type encoded automatically. 129 | 130 | _Note:_ This has worked really well for me on Lucee, however, it might not work as well with ColdFusion due to its less accurate variable typing. In both cases, keep in mind that data will typed as a `Number` if an `isNumeric()` check returns true, which it may well do in situations you do not expect. In addition, when using ColdFusion the `serializeJSON()` function seems to want to encode anything that can be cast as a number to a number in the JSON string, so the JSON string has to be edited by `dynamodb.cfc` before posting it to DynamoDB. It seems to work in my (limited) testing, but it is quite possible I have missed some of the encoding mistakes, which would lead to DynamoDB returning errors for invalidly encoded JSON strings. 131 | 132 | Similarly when you retrieve data from a DynamoDB table, it will be automatically decoded for you, so that you get back a struct of data for each row. 133 | 134 | Here is an example: 135 | 136 | ```cfc 137 | // putting an item with a HASH key of `id = 1` 138 | // note that table HASH and RANGE key values are included in the item struct 139 | item = { 140 | 'id': 1, 141 | 'thisisnull': javaCast( 'null', '' ), 142 | 'number': 3.45, 143 | 'nested': { 144 | 'list': [ 'foo', 2 ] 145 | } 146 | }; 147 | putItemResult = aws.dynamodb.putItem( 'myTableName', item ); 148 | 149 | // getting that item 150 | itemFromDynamoDB = aws.dynamodb.getItem( 'myTableName', { 'id': 1 } ); 151 | ``` 152 | 153 | If you do not want your data to be type encoded automatically you have two options. The first is to pass the argument `typeDefinitions = typeDefStruct` into a method where `typeDefStruct` is a struct whose keys match keys in your item, and whose values are the types of the key values in your item. Where a key match is found, `dynamodb.cfc` will use the specified type for encoding rather than attempting to determine the type. 154 | 155 | The other option is to pass `dataTypeEncoding = false` to any method, and data will be not be encoded at all. (Thus you will need to encode items yourself.) 156 | 157 | _Note:_ If you want to use non-native CFML types such as the various set types, you will need to use one of these latter two options when putting items. 158 | 159 | ### Polly 160 | 161 | The following operations have been implemented: DescribeVoices, SynthesizeSpeech. 162 | 163 | You can configure the default language and default engine by using a `constructorArgs` struct in your module settings (or by passing this struct in at init if you are using this as a standalone library): 164 | 165 | ```cfc 166 | { 167 | translate: { 168 | defaultLanguageCode: 'es-ES', 169 | defaultEngine: 'neural' 170 | } 171 | } 172 | ``` 173 | 174 | Example of synthesizing text using "Kendra" voice for default language (en-US). 175 | 176 | ```cfc 177 | response = aws.polly.synthesizeSpeech( 'Hello World', 'Kendra' ); 178 | // The stream data is in: response.rawData 179 | ``` 180 | 181 | ### Rekognition 182 | 183 | The following basic image processing operations have been implemented: DetectText, DetectFaces, RecognizeCelebrities, DetectLabels, DetectModerationLabels. 184 | 185 | Here is an example for detecting unsafe content in an image: 186 | 187 | ```cfc 188 | imageBinary = fileReadBinary(expandPath('/path/to/image.jpg')); 189 | imageBase64 = binaryEncode(imageBinary, 'base64'); 190 | 191 | response = aws.rekognition.detectModerationLabels({'Bytes': imageBase64}); 192 | moderationlabels = response.data.ModerationLabels; 193 | // moderationlabels is an array of moderation label structs 194 | // see https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html 195 | ``` 196 | 197 | ### S3 198 | 199 | Most basic operations are supported for S3. However, there is currently no support for updating bucket settings. Support for encrypted buckets and objects is also missing. 200 | 201 | TODO: provide an example for using the `getFormPostParams()` method. 202 | 203 | ### Secrets Manager 204 | 205 | Only the GetSecretValue operation has been implemented. Here's an example of using it: 206 | 207 | ```cfc 208 | response = aws.secretsmanager.getSecretValue( 'YourSecretId' ); 209 | secretValue = response.data.SecretString; 210 | ``` 211 | 212 | ### SSM 213 | 214 | Only the getParameter and getParameters operations have been implemented. Here's an example of using it: 215 | 216 | ```cfc 217 | response = aws.ssm.getParameter( 'YourParameterName', true ); 218 | decryptedValue = response.data.Parameter.Value; 219 | ``` 220 | 221 | ### Translate 222 | 223 | You can configure the default source and target languages by using a `constructorArgs` struct in your module settings (or by passing this struct in at init if you are using this as a standalone library): 224 | 225 | ```cfc 226 | { 227 | translate: { 228 | defaultSourceLanguageCode: 'es', 229 | defaultTargetLanguageCode: 'en' 230 | } 231 | } 232 | ``` 233 | 234 | Also you can override in the translate call: 235 | 236 | ```cfc 237 | response = aws.translate.translateText( Text = 'house', SourceLanguageCode = 'en', TargetLanguageCode = 'de' ); 238 | // The translated text is in: response.data.TranslatedText; 239 | ``` 240 | 241 | You can see the supported language codes by the service in the api docs: 242 | -------------------------------------------------------------------------------- /services/ec2.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'ec2'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.utils = variables.api.getUtils(); 11 | variables.apiVersion = arguments.settings.apiVersion; 12 | return this; 13 | } 14 | 15 | /** 16 | * Describes the specified instances or all instances. 17 | * https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html 18 | * @InstanceIds The IDs of the instances one wishes to describe 19 | * @DryRun Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation. 20 | */ 21 | public any function DescribeInstances( 22 | required array InstanceIds = [ ], 23 | boolean DryRun = false 24 | ) { 25 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 26 | var queryParams = { 'Action': 'DescribeInstances' }; 27 | 28 | queryParams[ 'DryRun' ] = arguments.DryRun; 29 | 30 | parseInstanceIds( arguments.InstanceIds, queryParams ); 31 | 32 | var apiResponse = apiCall( 33 | requestSettings, 34 | 'GET', 35 | '/', 36 | queryParams 37 | ); 38 | if ( apiResponse.statusCode == 200 ) { 39 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 40 | } 41 | return apiResponse; 42 | } 43 | 44 | /** 45 | * Starts an Amazon EBS-backed instance that you've previously stopped. 46 | * https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StartInstances.html 47 | * @InstanceIds The IDs of the instances one wishes to start 48 | * @DryRun Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation. 49 | */ 50 | public any function StartInstances( 51 | required array InstanceIds = [ ], 52 | boolean DryRun = false 53 | ) { 54 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 55 | var queryParams = { 'Action': 'StartInstances' }; 56 | 57 | queryParams[ 'DryRun' ] = arguments.DryRun; 58 | parseInstanceIds( arguments.InstanceIds, queryParams ); 59 | 60 | var apiResponse = apiCall( 61 | requestSettings, 62 | 'GET', 63 | '/', 64 | queryParams 65 | ); 66 | if ( apiResponse.statusCode == 200 ) { 67 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 68 | } 69 | return apiResponse; 70 | } 71 | 72 | /** 73 | * Requests a reboot of the specified instances. This operation is asynchronous; it only queues a request to reboot the specified instances. The operation succeeds if the instances are valid and belong to you. Requests to reboot terminated instances are ignored. 74 | * https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RebootInstances.html 75 | * @InstanceIds The IDs of the instances one wishes to reboot 76 | * @DryRun Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation. 77 | */ 78 | public any function RebootInstances( 79 | required array InstanceIds = [ ], 80 | boolean DryRun = false 81 | ) { 82 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 83 | var queryParams = { 'Action': 'RebootInstances' }; 84 | 85 | queryParams[ 'DryRun' ] = arguments.DryRun; 86 | parseInstanceIds( arguments.InstanceIds, queryParams ); 87 | 88 | var apiResponse = apiCall( 89 | requestSettings, 90 | 'GET', 91 | '/', 92 | queryParams 93 | ); 94 | if ( apiResponse.statusCode == 200 ) { 95 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 96 | } 97 | return apiResponse; 98 | } 99 | 100 | /** 101 | * Stops a running Amazon EBS-backed instance. 102 | * https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StopInstances.html 103 | * @InstanceIds The ID of the instances one wishes to stop 104 | * @DryRun Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation. 105 | * @Force Forces the instances to stop. The instances do not have an opportunity to flush file system caches or file system metadata. If you use this option, you must perform file system check and repair procedures. This option is not recommended for Windows instances. 106 | * @Hibernate Hibernates the instance if the instance was enabled for hibernation at launch. If the instance cannot hibernate successfully, a normal shutdown occurs. 107 | */ 108 | public any function StopInstances( 109 | required array InstanceIds = [ ], 110 | boolean Hibernate = false, 111 | boolean DryRun = false, 112 | boolean Force = false 113 | ) { 114 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 115 | var queryParams = { 'Action': 'StopInstances' }; 116 | 117 | queryParams[ 'DryRun' ] = arguments.DryRun; 118 | queryParams[ 'Hibernate' ] = arguments.Hibernate; 119 | queryParams[ 'Force' ] = arguments.Force; 120 | parseInstanceIds( arguments.InstanceIds, queryParams ); 121 | 122 | var apiResponse = apiCall( 123 | requestSettings, 124 | 'GET', 125 | '/', 126 | queryParams 127 | ); 128 | if ( apiResponse.statusCode == 200 ) { 129 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 130 | } 131 | return apiResponse; 132 | } 133 | 134 | /** 135 | * Starts an Amazon EBS-backed instance that you've previously stopped. 136 | * https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceAttribute.html 137 | * @InstanceIds The IDs of the instances one wishes to start 138 | * @DryRun Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation. 139 | * @Attribute The name of the attribute. Valid Values: instanceType | kernel | ramdisk | userData | disableApiTermination | instanceInitiatedShutdownBehavior | rootDeviceName | blockDeviceMapping | productCodes | sourceDestCheck | groupSet | ebsOptimized | sriovNetSupport | enaSupport | enclaveOptions 140 | * @Value A new value for the attribute. Use only with the kernel, ramdisk, userData, disableApiTermination, or instanceInitiatedShutdownBehavior attribute. 141 | * @InstanceType Changes the instance type to the specified value.If the instance type is not valid, the error returned is InvalidInstanceAttributeValue. For more information, see Instance types in the Amazon EC2 User Guide. https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html 142 | * 143 | * Type CPU RAM 144 | * c5.large 2 4 145 | * c5.xlarge 4 8 146 | * c5.2xlarge 8 16 147 | * c5.4xlarge 16 32 148 | * c5.9xlarge 36 72 149 | * c5.12xlarge 48 96 150 | * c5.18xlarge 72 144 151 | * c5.24xlarge 96 192 152 | */ 153 | public any function ModifyInstanceAttribute( 154 | required array InstanceIds = [ ], 155 | string InstanceType = '', 156 | string Attribute = '', 157 | string Value = '', 158 | boolean DryRun = false 159 | ) { 160 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 161 | var queryParams = { 'Action': 'StartInstances' }; 162 | 163 | queryParams[ 'DryRun' ] = arguments.DryRun; 164 | 165 | if ( len( arguments.Attribute ) ) queryParams[ 'Attribute' ] = arguments.Attribute; 166 | if ( len( arguments.Value ) ) queryParams[ 'Value' ] = arguments.Value; 167 | if ( len( arguments.InstanceType ) ) queryParams[ 'InstanceType.Value' ] = arguments.InstanceType; 168 | parseInstanceIds( arguments.InstanceIds, queryParams ); 169 | 170 | var apiResponse = apiCall( 171 | requestSettings, 172 | 'GET', 173 | '/', 174 | queryParams 175 | ); 176 | if ( apiResponse.statusCode == 200 ) { 177 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 178 | } 179 | return apiResponse; 180 | } 181 | 182 | // private 183 | 184 | private string function getHost( 185 | required string region 186 | ) { 187 | return variables.service & '.' & region & '.amazonaws.com'; 188 | } 189 | 190 | private any function apiCall( 191 | required struct requestSettings, 192 | string httpMethod = 'GET', 193 | string path = '/', 194 | struct queryParams = { }, 195 | struct headers = { }, 196 | any payload = '' 197 | ) { 198 | var host = getHost( requestSettings.region ); 199 | 200 | if ( isStruct( payload ) ) { 201 | structAppend( payload, { 'Version': variables.apiVersion }, false ); 202 | structAppend( headers, { 'Content-Type': 'application/x-www-form-urlencoded' }, false ); 203 | payload = utils.parseQueryParams( payload ); 204 | } else { 205 | structAppend( queryParams, { 'Version': variables.apiVersion }, false ); 206 | } 207 | return api.call( 208 | variables.service, 209 | host, 210 | requestSettings.region, 211 | httpMethod, 212 | path, 213 | queryParams, 214 | headers, 215 | payload, 216 | requestSettings.awsCredentials 217 | ); 218 | } 219 | 220 | private void function parseInstanceIds( 221 | required array InstanceIds = [ ], 222 | struct queryParams 223 | ) { 224 | if ( len( arguments.InstanceIds ) ) { 225 | InstanceIds.each( function( e, i ) { 226 | queryParams[ 'InstanceId.#i#' ] = e; 227 | } ); 228 | } 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /com/credentials.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.iamRolePath = '169.254.169.254/latest/meta-data/iam/security-credentials/'; 4 | variables.ecsEndpoint = '169.254.170.2'; 5 | 6 | public any function init( 7 | string awsKey = '', 8 | string awsSecretKey = '', 9 | any api 10 | ) { 11 | variables.api = api; 12 | variables.credentials = resolveCredentials( awsKey, awsSecretKey ); 13 | return this; 14 | } 15 | 16 | public struct function getCredentials() { 17 | if ( 18 | !isNull( variables.credentials.expires ) && 19 | variables.credentials.expires <= now() 20 | ) { 21 | variables.credentials = refreshCredentials( variables.credentials ); 22 | } 23 | return variables.credentials.keys; 24 | } 25 | 26 | public struct function defaultCredentials( 27 | string awsKey = '', 28 | string awsSecretKey = '', 29 | string token = '' 30 | ) { 31 | return { awsKey: awsKey, awsSecretKey: awsSecretKey, token: token }; 32 | } 33 | 34 | private function resolveCredentials( 35 | awsKey, 36 | awsSecretKey 37 | ) { 38 | // explicit 39 | var credentials = { 40 | keys: defaultCredentials( awsKey, awsSecretKey ), 41 | type: 'explicit', 42 | expires: javacast( 'null', '' ), 43 | refresh: { } 44 | }; 45 | if ( validCredentials( credentials ) ) { 46 | return credentials; 47 | } 48 | 49 | var utils = api.getUtils(); 50 | 51 | 52 | // environment 53 | var credentials = { 54 | keys: { 55 | 'awsKey': utils.getSystemSetting( 'AWS_ACCESS_KEY_ID', '' ), 56 | 'awsSecretKey': utils.getSystemSetting( 'AWS_SECRET_ACCESS_KEY', '' ), 57 | 'token': utils.getSystemSetting( 'AWS_SESSION_TOKEN', '' ) 58 | }, 59 | type: 'environment', 60 | expires: javacast( 'null', '' ), 61 | refresh: { } 62 | }; 63 | if ( validCredentials( credentials ) ) { 64 | return credentials; 65 | } 66 | 67 | var userHome = utils.getSystemSetting( 'user.home' ).replace( '\', '/', 'all' ); 68 | var awsProfile = utils.getSystemSetting( 'AWS_PROFILE', 'default' ); 69 | 70 | 71 | // AWS credentials file 72 | var credentialsFile = utils.getSystemSetting( 'AWS_SHARED_CREDENTIALS_FILE', userHome & '/.aws/credentials' ); 73 | 74 | if ( fileExists( credentialsFile ) ) { 75 | var credentialProcess = getProfileString( credentialsFile, awsProfile, 'credential_process' ).trim(); 76 | if ( len( credentialProcess ) ) { 77 | var credentials = credentialsFromProcess( credentialProcess ); 78 | if ( validCredentials( credentials ) ) { 79 | return credentials; 80 | } 81 | } 82 | 83 | var credentials = { 84 | keys: { 85 | 'awsKey': getProfileString( credentialsFile, awsProfile, 'aws_access_key_id' ).trim(), 86 | 'awsSecretKey': getProfileString( credentialsFile, awsProfile, 'aws_secret_access_key' ).trim(), 87 | 'token': getProfileString( credentialsFile, awsProfile, 'aws_session_token' ).trim() 88 | }, 89 | type: 'credentialsFile', 90 | expires: javacast( 'null', '' ), 91 | refresh: { } 92 | }; 93 | if ( validCredentials( credentials ) ) { 94 | return credentials; 95 | } 96 | } 97 | 98 | 99 | // AWS config file 100 | var configFile = utils.getSystemSetting( 'AWS_CONFIG_FILE', userHome & '/.aws/config' ); 101 | if ( fileExists( configFile ) ) { 102 | var awsConfigProfile = awsProfile == 'default' ? 'default' : 'profile #awsProfile#'; 103 | 104 | var credentialProcess = getProfileString( configFile, awsConfigProfile, 'credential_process' ).trim(); 105 | if ( len( credentialProcess ) ) { 106 | var credentials = credentialsFromProcess( credentialProcess ); 107 | if ( validCredentials( credentials ) ) { 108 | return credentials; 109 | } 110 | } 111 | 112 | var sso_account_id = getProfileString( configFile, awsConfigProfile, 'sso_account_id' ).trim(); 113 | var sso_role_name = getProfileString( configFile, awsConfigProfile, 'sso_role_name' ).trim(); 114 | var sso_session = getProfileString( configFile, awsConfigProfile, 'sso_session' ).trim(); 115 | 116 | if ( len( sso_account_id ) && len( sso_role_name ) ) { 117 | if ( len( sso_session ) ) { 118 | var ssoSessionProfile = 'sso-session #sso_session#'; 119 | var sso_start_url = getProfileString( configFile, ssoSessionProfile, 'sso_start_url' ).trim(); 120 | var sso_region = getProfileString( configFile, ssoSessionProfile, 'sso_region' ).trim(); 121 | var cacheKey = lCase( hash( sso_session, 'SHA-1' ) ); 122 | } else { 123 | var sso_start_url = getProfileString( configFile, awsConfigProfile, 'sso_start_url' ).trim(); 124 | var sso_region = getProfileString( configFile, awsConfigProfile, 'sso_region' ).trim(); 125 | var cacheKey = lCase( hash( sso_start_url, 'SHA-1' ) ); 126 | } 127 | 128 | if ( len( sso_start_url ) && len( sso_region ) ) { 129 | var cacheFilePath = userHome & '/.aws/sso/cache/#cacheKey#.json'; 130 | if ( fileExists( cacheFilePath ) ) { 131 | var cacheData = deserializeJSON( fileRead( cacheFilePath ) ); 132 | var expiresAt = parseDateTime( cacheData.expiresAt ); 133 | if ( expiresAt >= now() ) { 134 | var httpArgs = { 135 | 'path': 'portal.sso.#sso_region#.amazonaws.com/federation/credentials', 136 | 'useSSL': true, 137 | 'headers': { 'x-amz-sso_bearer_token': cacheData.accessToken }, 138 | 'queryParams': { 'account_id': sso_account_id, 'role_name': sso_role_name } 139 | }; 140 | 141 | var credentials = fetchCredentials( sso, httpArgs ); 142 | if ( validCredentials( credentials ) ) { 143 | return credentials; 144 | } 145 | } 146 | } 147 | } 148 | } 149 | } 150 | 151 | 152 | // IAM role (ECS) 153 | var relativeUri = utils.getSystemSetting( 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI', '' ); 154 | if ( len( relativeUri ) ) { 155 | var httpArgs = { 'path': variables.ecsEndpoint & relativeUri }; 156 | var credentials = fetchCredentials( 'ecsContainer', httpArgs ); 157 | if ( validCredentials( credentials ) ) { 158 | return credentials; 159 | } 160 | } 161 | 162 | 163 | // IAM role (EC2) 164 | try { 165 | var iamRole = requestIamRole(); 166 | if ( len( iamRole ) ) { 167 | var httpArgs = { 'path': variables.iamRolePath & iamRole }; 168 | var credentials = fetchCredentials( 'iamRole', httpArgs ); 169 | if ( validCredentials( credentials ) ) { 170 | return credentials; 171 | } 172 | } 173 | } catch ( any e ) { 174 | // pass 175 | } 176 | 177 | throw( type = 'aws.com.credentials', message = 'Unable to resolve AWS credentials.' ); 178 | } 179 | 180 | private boolean function validCredentials( 181 | credentials 182 | ) { 183 | return len( credentials.keys.awsKey ) && len( credentials.keys.awsSecretKey ); 184 | } 185 | 186 | private struct function refreshCredentials( 187 | credentials 188 | ) { 189 | if ( credentials.type == 'credentialProcess' ) { 190 | return credentialsFromProcess( credentials.refresh.credentialProcess ); 191 | } 192 | if ( 193 | credentials.type == 'ecsContainer' || 194 | credentials.type == 'iamRole' || 195 | credentials.type == 'sso' 196 | ) { 197 | return fetchCredentials( credentials.type, credentials.refresh.httpArgs ); 198 | } 199 | throw( type = 'aws.com.credentials', message = 'Unable to refresh AWS credentials.' ); 200 | } 201 | 202 | private struct function credentialsFromProcess( 203 | credentialProcess 204 | ) { 205 | var data = ''; 206 | cfexecute( name = credentialProcess, variable = "data" ); 207 | data = deserializeJSON( data ); 208 | return { 209 | keys: { 'awsKey': data.AccessKeyId, 'awsSecretKey': data.SecretAccessKey, 'token': data.SessionToken }, 210 | type: 'credentialProcess', 211 | expires: parseDateTime( data.Expiration ), 212 | refresh: { credentialProcess: credentialProcess } 213 | }; 214 | } 215 | 216 | private struct function fetchCredentials( 217 | credentialsType, 218 | httpArgs 219 | ) { 220 | var args = { 'httpMethod': 'get', 'useSSL': false }; 221 | structAppend( args, httpArgs ); 222 | var req = api.getHttpService().makeHttpRequest( argumentCollection = args ); 223 | var data = deserializeJSON( req.filecontent ); 224 | 225 | if ( credentialsType == 'sso' ) { 226 | var keys = { 227 | 'awsKey': data.roleCredentials.accessKeyId, 228 | 'awsSecretKey': data.roleCredentials.secretAccessKey, 229 | 'token': data.roleCredentials.sessionToken 230 | }; 231 | var epochDate = createObject( 'java', 'java.util.Date' ).init( javacast( 'int', 0 ) ); 232 | var expires = dateAdd( 'l', roleCredentials.expiration, variables.epochDate ); 233 | } else { 234 | var keys = { 'awsKey': data.AccessKeyId, 'awsSecretKey': data.SecretAccessKey, 'token': data.Token }; 235 | var expires = parseDateTime( data.Expiration ); 236 | } 237 | 238 | return { 239 | keys: keys, 240 | type: credentialsType, 241 | expires: expires, 242 | refresh: { httpArgs: httpArgs } 243 | }; 244 | } 245 | 246 | private string function requestIamRole() { 247 | var httpArgs = { }; 248 | httpArgs[ 'httpMethod' ] = 'get'; 249 | httpArgs[ 'path' ] = iamRolePath; 250 | httpArgs[ 'useSSL' ] = false; 251 | httpArgs[ 'timeout' ] = 1; 252 | var req = api.getHttpService().makeHttpRequest( argumentCollection = httpArgs ); 253 | if ( listFirst( req.statuscode, ' ' ) == 408 ) return ''; 254 | return req.filecontent; 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /services/secretsmanager.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'secretsmanager'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /** 15 | * Retrieves the contents of the encrypted fields SecretString or SecretBinary from the specified version of a secret, whichever contains content. 16 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html 17 | * @SecretId Specifies the secret containing the version that you want to retrieve. You can specify either the Amazon Resource Name (ARN) or the friendly name of the secret. 18 | */ 19 | public any function getSecretValue( 20 | required string SecretId 21 | ) { 22 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 23 | var payload = { 'SecretId': arguments.SecretId }; 24 | return apiCall( requestSettings, 'GetSecretValue', payload ); 25 | } 26 | 27 | /** 28 | * Retrieves the details of a secret. It does not include the encrypted secret value. Secrets Manager only returns fields that have a value in the response. 29 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DescribeSecret.html 30 | */ 31 | public any function describeSecret( 32 | required string SecretId 33 | ) { 34 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 35 | var payload = { 'SecretId': arguments.SecretId }; 36 | return apiCall( requestSettings, 'DescribeSecret', payload ); 37 | } 38 | 39 | /** 40 | * Create a new secret 41 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html 42 | */ 43 | public any function createSecret( 44 | required string Name, 45 | any SecretString, 46 | any SecretBinary, 47 | string Description = '', 48 | string KmsKeyId, 49 | array Tags, 50 | string ClientRequestToken = createUUID(), 51 | array AddReplicaRegions, 52 | boolean ForceOverwriteReplicaSecret 53 | ) { 54 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 55 | var payload = { 56 | 'Name': arguments.Name, 57 | 'Description': arguments.Description, 58 | 'ClientRequestToken': arguments.ClientRequestToken 59 | }; 60 | if ( structKeyExists( arguments, 'SecretString' ) ) { 61 | payload[ 'SecretString' ] = isSimpleValue( arguments.SecretString ) ? arguments.SecretString : serializeJSON( 62 | arguments.SecretString 63 | ); 64 | } else if ( structKeyExists( arguments, 'SecretBinary' ) ) { 65 | payload[ 'SecretBinary' ] = arguments.SecretBinary; 66 | } 67 | if ( structKeyExists( arguments, 'KmsKeyId' ) ) { 68 | payload[ 'KmsKeyId' ] = arguments.KmsKeyId; 69 | } 70 | if ( structKeyExists( arguments, 'Tags' ) && arrayLen( arguments.Tags ) ) { 71 | payload[ 'Tags' ] = arguments.Tags; 72 | } 73 | if ( structKeyExists( arguments, 'AddReplicaRegions' ) && arrayLen( arguments.AddReplicaRegions ) ) { 74 | payload[ 'AddReplicaRegions' ] = arguments.AddReplicaRegions; 75 | } 76 | if ( structKeyExists( arguments, 'ForceOverwriteReplicaSecret' ) ) { 77 | payload[ 'ForceOverwriteReplicaSecret' ] = arguments.ForceOverwriteReplicaSecret; 78 | } 79 | return apiCall( requestSettings, 'CreateSecret', payload ); 80 | } 81 | 82 | /** 83 | * Updates an existing secret 84 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_UpdateSecret.html 85 | */ 86 | public any function updateSecret( 87 | required string SecretId, 88 | required string Name, 89 | any SecretString, 90 | any SecretBinary, 91 | string Description = '', 92 | string KmsKeyId, 93 | string ClientRequestToken = createUUID() 94 | ) { 95 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 96 | var payload = { 97 | 'SecretId': arguments.SecretId, 98 | 'Name': arguments.Name, 99 | 'Description': arguments.Description, 100 | 'ClientRequestToken': arguments.ClientRequestToken 101 | }; 102 | if ( structKeyExists( arguments, 'SecretString' ) ) { 103 | payload[ 'SecretString' ] = isSimpleValue( arguments.SecretString ) ? arguments.SecretString : serializeJSON( 104 | arguments.SecretString 105 | ); 106 | } else if ( structKeyExists( arguments, 'SecretBinary' ) ) { 107 | payload[ 'SecretBinary' ] = arguments.SecretBinary; 108 | } 109 | if ( structKeyExists( arguments, 'KmsKeyId' ) ) { 110 | payload[ 'KmsKeyId' ] = arguments.KmsKeyId; 111 | } 112 | return apiCall( requestSettings, 'UpdateSecret', payload ); 113 | } 114 | 115 | /** 116 | * Updates an existing secret's value only 117 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_PutSecretValue.html 118 | */ 119 | public any function PutSecretValue( 120 | required string SecretId, 121 | any SecretString, 122 | any SecretBinary, 123 | array VersionStages, 124 | string ClientRequestToken = createUUID() 125 | ) { 126 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 127 | var payload = { 'SecretId': arguments.SecretId, 'ClientRequestToken': arguments.ClientRequestToken }; 128 | if ( structKeyExists( arguments, 'SecretString' ) ) { 129 | payload[ 'SecretString' ] = isSimpleValue( arguments.SecretString ) ? arguments.SecretString : serializeJSON( 130 | arguments.SecretString 131 | ); 132 | } else if ( structKeyExists( arguments, 'SecretBinary' ) ) { 133 | payload[ 'SecretBinary' ] = arguments.SecretBinary; 134 | } 135 | if ( structKeyExists( arguments, 'VersionStages' ) && arrayLen( arguments.VersionStages ) ) { 136 | payload[ 'VersionStages' ] = arguments.VersionStages; 137 | } 138 | return apiCall( requestSettings, 'PutSecretValue', payload ); 139 | } 140 | 141 | /** 142 | * Delete a secret 143 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_DeleteSecret.html 144 | */ 145 | public any function deleteSecret( 146 | required string SecretId 147 | ) { 148 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 149 | var payload = { 'SecretId': arguments.SecretId }; 150 | return apiCall( requestSettings, 'DeleteSecret', payload ); 151 | } 152 | 153 | /** 154 | * Remove replication from a secret 155 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_RemoveRegionsFromReplication.html 156 | */ 157 | public any function removeRegionsFromReplication( 158 | required string SecretId, 159 | required array RemoveReplicaRegions 160 | ) { 161 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 162 | var payload = { 'SecretId': arguments.SecretId, 'RemoveReplicaRegions': arguments.RemoveReplicaRegions }; 163 | return apiCall( requestSettings, 'RemoveRegionsFromReplication', payload ); 164 | } 165 | 166 | /** 167 | * Restore a secret 168 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_RestoreSecret.html 169 | */ 170 | public any function restoreSecret( 171 | required string SecretId 172 | ) { 173 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 174 | var payload = { 'SecretId': arguments.SecretId }; 175 | return apiCall( requestSettings, 'RestoreSecret', payload ); 176 | } 177 | 178 | /** 179 | * Lists secrets 180 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_ListSecrets.html 181 | */ 182 | public any function listSecrets( 183 | array Filters, 184 | boolean IncludePlannedDeletion = false, 185 | numeric MaxResults, // between 1-100 186 | string NextToken, 187 | string SortOrder 188 | ) { 189 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 190 | var payload = { 'IncludePlannedDeletion': arguments.IncludePlannedDeletion }; 191 | if ( structKeyExists( arguments, 'Filters' ) && arrayLen( arguments.Filters ) ) { 192 | payload[ 'Filters' ] = arguments.Filters; 193 | } 194 | if ( structKeyExists( arguments, 'MaxResults' ) ) { 195 | payload[ 'MaxResults' ] = arguments.MaxResults; 196 | } 197 | if ( structKeyExists( arguments, 'NextToken' ) ) { 198 | payload[ 'NextToken' ] = arguments.NextToken; 199 | } 200 | if ( structKeyExists( arguments, 'SortOrder' ) ) { 201 | payload[ 'SortOrder' ] = arguments.SortOrder; 202 | } 203 | return apiCall( requestSettings, 'ListSecrets', payload ); 204 | } 205 | 206 | /** 207 | * Get random password 208 | * https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetRandomPassword.html 209 | */ 210 | public any function getRandomPassword( 211 | required numeric PasswordLength, 212 | string ExcludeCharacters = '', 213 | boolean ExcludeLowercase = false, 214 | boolean ExcludeNumbers = false, 215 | boolean ExcludePunctuation = false, 216 | boolean ExcludeUppercase = false, 217 | boolean IncludeSpace = false, 218 | boolean RequireEachIncludedType = true 219 | ) { 220 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 221 | var payload = { 222 | 'PasswordLength': arguments.PasswordLength, 223 | 'ExcludeCharacters': arguments.ExcludeCharacters, 224 | 'ExcludeLowercase': arguments.ExcludeLowercase, 225 | 'ExcludeNumbers': arguments.ExcludeNumbers, 226 | 'ExcludePunctuation': arguments.ExcludePunctuation, 227 | 'ExcludeUppercase': arguments.ExcludeUppercase, 228 | 'IncludeSpace': arguments.IncludeSpace, 229 | 'RequireEachIncludedType': arguments.RequireEachIncludedType 230 | }; 231 | return apiCall( requestSettings, 'GetRandomPassword', payload ); 232 | } 233 | 234 | public string function getHost( 235 | required string region 236 | ) { 237 | return variables.service & '.' & region & '.amazonaws.com'; 238 | } 239 | 240 | private any function apiCall( 241 | required struct requestSettings, 242 | required string target, 243 | struct payload = { } 244 | ) { 245 | var host = getHost( requestSettings.region ); 246 | var payloadString = serializeJSON( payload ); 247 | 248 | var headers = { }; 249 | headers[ 'X-Amz-Target' ] = 'secretsmanager' & '.' & arguments.target; 250 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 251 | 252 | var apiResponse = api.call( 253 | variables.service, 254 | host, 255 | requestSettings.region, 256 | 'POST', 257 | '/', 258 | { }, 259 | headers, 260 | payloadString, 261 | requestSettings.awsCredentials 262 | ); 263 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 264 | 265 | return apiResponse; 266 | } 267 | 268 | } 269 | -------------------------------------------------------------------------------- /services/sns.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'sns'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.utils = variables.api.getUtils(); 11 | variables.apiVersion = arguments.settings.apiVersion; 12 | return this; 13 | } 14 | 15 | /** 16 | * Returns a list of the requester's topics. 17 | * http://docs.aws.amazon.com/sns/latest/api/API_ListTopics.html 18 | * @NextToken Token to pass along to the next listTopics request. This element is returned if there are more subscriptions to retrieve. 19 | */ 20 | public any function listTopics( 21 | string NextToken = '' 22 | ) { 23 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 24 | var queryParams = { 'Action': 'ListTopics' }; 25 | 26 | if ( len( arguments.NextToken ) ) queryParams[ 'NextToken' ] = arguments.NextToken; 27 | 28 | var apiResponse = apiCall( 29 | requestSettings, 30 | 'GET', 31 | '/', 32 | queryParams 33 | ); 34 | if ( apiResponse.statusCode == 200 ) { 35 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 36 | } 37 | return apiResponse; 38 | } 39 | 40 | /** 41 | * Creates a topic to which notifications can be published. Users can create at most 100,000 topics. 42 | * For more information, see http://aws.amazon.com/sns. This action is idempotent, so if the requester 43 | * already owns a topic with the specified name, that topic's ARN is returned without creating a new topic. 44 | * http://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html 45 | * @Name The name of the topic you want to create. 46 | */ 47 | public any function createTopic( 48 | required string Name 49 | ) { 50 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 51 | var queryParams = { 'Action': 'CreateTopic', 'Name': arguments.Name }; 52 | var apiResponse = apiCall( 53 | requestSettings, 54 | 'GET', 55 | '/', 56 | queryParams 57 | ); 58 | if ( apiResponse.statusCode == 200 ) { 59 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 60 | } 61 | return apiResponse; 62 | } 63 | 64 | /** 65 | * Deletes a topic and all its subscriptions. 66 | * Deleting a topic might prevent some messages previously sent to the topic from being delivered to subscribers. 67 | * This action is idempotent, so deleting a topic that does not exist does not result in an error. 68 | * http://docs.aws.amazon.com/sns/latest/api/API_DeleteTopic.html 69 | * @TopicArn The ARN of the topic you want to delete. 70 | */ 71 | public any function deleteTopic( 72 | required string TopicArn 73 | ) { 74 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 75 | var queryParams = { 'Action': 'DeleteTopic', 'TopicArn': arguments.TopicArn }; 76 | var apiResponse = apiCall( 77 | requestSettings, 78 | 'GET', 79 | '/', 80 | queryParams 81 | ); 82 | if ( apiResponse.statusCode == 200 ) { 83 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 84 | } 85 | return apiResponse; 86 | } 87 | 88 | /** 89 | * Returns a list of the requester's subscriptions. 90 | * http://http://docs.aws.amazon.com/sns/latest/api/API_ListSubscriptions.html 91 | * @NextToken Token to pass along to the next ListSubscriptions request. This element is returned if there are more subscriptions to retrieve. 92 | */ 93 | public any function listSubscriptions( 94 | string NextToken = '' 95 | ) { 96 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 97 | var queryParams = { 'Action': 'ListSubscriptions' }; 98 | 99 | if ( len( arguments.NextToken ) ) queryParams[ 'NextToken' ] = arguments.NextToken; 100 | 101 | var apiResponse = apiCall( 102 | requestSettings, 103 | 'GET', 104 | '/', 105 | queryParams 106 | ); 107 | if ( apiResponse.statusCode == 200 ) { 108 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 109 | } 110 | return apiResponse; 111 | } 112 | 113 | /** 114 | * Returns a list of the subscriptions to a specific topic. 115 | * http://docs.aws.amazon.com/sns/latest/api/API_ListSubscriptionsByTopic.html 116 | * @TopicArn The ARN of the topic for which you wish to find subscriptions. 117 | * @NextToken Token to pass along to the next ListSubscriptionsByTopic request. This element is returned if there are more subscriptions to retrieve. 118 | */ 119 | public any function listSubscriptionsByTopic( 120 | required string TopicArn, 121 | string NextToken = '' 122 | ) { 123 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 124 | var queryParams = { 'Action': 'ListSubscriptionsByTopic', 'TopicArn': arguments.TopicArn }; 125 | 126 | if ( len( arguments.NextToken ) ) queryParams[ 'NextToken' ] = arguments.NextToken; 127 | 128 | var apiResponse = apiCall( 129 | requestSettings, 130 | 'GET', 131 | '/', 132 | queryParams 133 | ); 134 | if ( apiResponse.statusCode == 200 ) { 135 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 136 | } 137 | return apiResponse; 138 | } 139 | 140 | /** 141 | * Sends a message to an Amazon SNS topic or sends a text message (SMS message) directly to a phone number. 142 | * If you send a message to a topic, Amazon SNS delivers the message to each endpoint that is subscribed to the topic. 143 | * The format of the message depends on the notification protocol for each subscribed endpoint. 144 | * You must specify a value for one of the PhoneNumber, TargetArn or TopicArn parameters. 145 | * http://docs.aws.amazon.com/sns/latest/api/API_Publish.html 146 | * @Message The ARN of the topic for which you wish to find subscriptions. This can be a JSON object in order to specify different formats for different protocals - see the documentation for examples. If you use a JSON object `MessageStructure` must be set to `json` 147 | * @MessageAttributes Message attributes for Publish action. 148 | * @MessageStructure Set MessageStructure to json if you want to send a different message for each protocol. 149 | * @PhoneNumber The phone number to which you want to deliver an SMS message. Use E.164 format. 150 | * @Subject Optional parameter to be used as the "Subject" line when the message is delivered to email endpoints. This field will also be included, if present, in the standard JSON messages delivered to other endpoints. 151 | * @TargetArn The target you want to publish to. 152 | * @TopicArn The topic you want to publish to. 153 | */ 154 | public any function publish( 155 | required string Message, 156 | struct MessageAttributes = { }, 157 | string MessageStructure = '', 158 | string PhoneNumber = '', 159 | string Subject = '', 160 | string TargetArn = '', 161 | string TopicArn = '' 162 | ) { 163 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 164 | var formParams = { 'Action': 'Publish', 'Message': arguments.Message }; 165 | for ( 166 | var key in [ 167 | 'MessageStructure', 168 | 'PhoneNumber', 169 | 'Subject', 170 | 'TargetArn', 171 | 'TopicArn' 172 | ] 173 | ) { 174 | if ( len( arguments[ key ] ) ) formParams[ key ] = arguments[ key ]; 175 | } 176 | 177 | if ( arguments.keyExists( 'MessageAttributes' ) ) { 178 | var i = 1; 179 | MessageAttributes.each( function( k, v ) { 180 | var dataType = 'String'; 181 | var valueType = 'StringValue'; 182 | 183 | if ( isBinary( v ) ) { 184 | dataType = 'Binary'; 185 | valueType = 'BinaryValue'; 186 | v = binaryEncode( v, 'base64' ); 187 | } else if ( isArray( v ) ) { 188 | dataType = 'String.Array'; 189 | v = serializeJSON( v ); 190 | } else if ( isNumeric( v ) ) { 191 | dataType = 'Number'; 192 | } 193 | 194 | formParams[ 'MessageAttributes.entry.#i#.Name' ] = k; 195 | formParams[ 'MessageAttributes.entry.#i#.Value.DataType' ] = dataType; 196 | formParams[ 'MessageAttributes.entry.#i#.Value.#valueType#' ] = v; 197 | 198 | i++; 199 | } ); 200 | } 201 | 202 | var apiResponse = apiCall( 203 | requestSettings, 204 | 'POST', 205 | '/', 206 | { }, 207 | { }, 208 | formParams 209 | ); 210 | if ( apiResponse.statusCode == 200 ) { 211 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 212 | } 213 | return apiResponse; 214 | } 215 | 216 | /** 217 | * Prepares to subscribe an endpoint by sending the endpoint a confirmation message. 218 | * To actually create a subscription, the endpoint owner must call the ConfirmSubscription action with the token from the confirmation message. 219 | * Confirmation tokens are valid for three days. 220 | * http://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html 221 | * @Endpoint The endpoint that you want to receive notifications. Endpoints vary by protocol. 222 | * @Protocol The protocol you want to use. Supported protocols: (http|https|email|email-json|sms|sqs|application|lambda) 223 | * @TopicArn The ARN of the topic you want to subscribe to. 224 | */ 225 | public any function subscribe( 226 | required string Endpoint, 227 | required string Protocol, 228 | required string TopicArn 229 | ) { 230 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 231 | var queryParams = { 'Action': 'Subscribe' }; 232 | for ( var key in [ 'Endpoint', 'Protocol', 'TopicArn' ] ) { 233 | if ( len( arguments[ key ] ) ) queryParams[ key ] = arguments[ key ]; 234 | } 235 | 236 | var apiResponse = apiCall( 237 | requestSettings, 238 | 'GET', 239 | '/', 240 | queryParams 241 | ); 242 | if ( apiResponse.statusCode == 200 ) { 243 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 244 | } 245 | return apiResponse; 246 | } 247 | 248 | /** 249 | * Deletes a subscription. 250 | * If the subscription requires authentication for deletion, only the owner of the subscription or the topic's owner can unsubscribe, and an AWS signature is required. 251 | * If the Unsubscribe call does not require authentication and the requester is not the subscription owner, a final cancellation message is delivered to the endpoint, 252 | * so that the endpoint owner can easily resubscribe to the topic if the Unsubscribe request was unintended. 253 | * http://docs.aws.amazon.com/sns/latest/api/API_Unsubscribe.html 254 | * @SubscriptionArn The ARN of the subscription to be deleted. 255 | */ 256 | public any function unsubscribe( 257 | required string SubscriptionArn 258 | ) { 259 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 260 | var queryParams = { 'Action': 'Unsubscribe', 'SubscriptionArn': arguments.SubscriptionArn }; 261 | 262 | var apiResponse = apiCall( 263 | requestSettings, 264 | 'GET', 265 | '/', 266 | queryParams 267 | ); 268 | if ( apiResponse.statusCode == 200 ) { 269 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 270 | } 271 | return apiResponse; 272 | } 273 | 274 | // private 275 | 276 | private string function getHost( 277 | required string region 278 | ) { 279 | return variables.service & '.' & region & '.amazonaws.com'; 280 | } 281 | 282 | private any function apiCall( 283 | required struct requestSettings, 284 | string httpMethod = 'GET', 285 | string path = '/', 286 | struct queryParams = { }, 287 | struct headers = { }, 288 | any payload = '' 289 | ) { 290 | var host = getHost( requestSettings.region ); 291 | 292 | if ( isStruct( payload ) ) { 293 | structAppend( payload, { 'Version': variables.apiVersion }, false ); 294 | structAppend( headers, { 'Content-Type': 'application/x-www-form-urlencoded' }, false ); 295 | payload = utils.parseQueryParams( payload ); 296 | } else { 297 | structAppend( queryParams, { 'Version': variables.apiVersion }, false ); 298 | } 299 | return api.call( 300 | variables.service, 301 | host, 302 | requestSettings.region, 303 | httpMethod, 304 | path, 305 | queryParams, 306 | headers, 307 | payload, 308 | requestSettings.awsCredentials 309 | ); 310 | } 311 | 312 | } 313 | -------------------------------------------------------------------------------- /services/sqs.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'sqs'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.utils = variables.api.getUtils(); 11 | variables.apiVersion = arguments.settings.apiVersion; 12 | return this; 13 | } 14 | 15 | public any function listQueues() { 16 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 17 | var apiResponse = apiCall( 18 | requestSettings, 19 | 'POST', 20 | '/', 21 | { 'Action': 'ListQueues' } 22 | ); 23 | if ( apiResponse.statusCode == 200 ) { 24 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 25 | } 26 | return apiResponse; 27 | } 28 | 29 | /** 30 | * Sends a message 31 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html 32 | * @queueName Required string. The name of the queue to send to (e.g. "123456789/my-sqs-queue"). 33 | * @message Required string. The message to post, text format. 34 | * @delaySeconds Optional numeric. The length of time, in seconds, for which to delay a specific message. 35 | * Valid values: 0 to 900. Maximum: 15 minutes. Messages with a positive DelaySeconds value become available for 36 | * processing after the delay period is finished. If you don't specify a value, the default value for the queue applies. 37 | * Note: When you set FifoQueue, you can't set DelaySeconds per message. You can set this parameter only on a queue level. 38 | * @messageAttributes Optional array. An array of message attributes to be added to the message. Each array item must contain a structure 39 | * containing 3 keys: Name, Value, DataType. String and Number are supported DataType values. 40 | * Example: [{'Name':'AttName','Value':'AttVal','DataType':'String'},{'Name':'AttName3','Value':34,'DataType':'Number'}] 41 | * @messageDeduplicationId Optional string. This parameter applies only to FIFO (first-in-first-out) queues. 42 | * The token used for deduplication of sent messages. 43 | * The maximum length of MessageDeduplicationId is 128 characters. MessageDeduplicationId can contain alphanumeric 44 | * characters (a-z, A-Z, 0-9) and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 45 | * @messageGroupId Optional string. This parameter applies only to FIFO (first-in-first-out) queues. 46 | * Note: MessageGroupId is required for FIFO queues. You can't use it for Standard queues. 47 | * The maximum length of MessageGroupId is 128 characters. messageGroupId can contain alphanumeric 48 | * characters (a-z, A-Z, 0-9) and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 49 | */ 50 | public any function sendMessage( 51 | required string queueName, 52 | required string message, 53 | numeric delaySeconds, 54 | array messageAttributes = [ ], 55 | string messageDeduplicationId, 56 | string messageGroupId 57 | ) { 58 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 59 | var payload = { 'Action': 'SendMessage' }; 60 | // prepare message and append to payload 61 | structAppend( payload, prepareMessage( argumentCollection = arguments ) ); 62 | var apiResponse = apiCall( 63 | requestSettings, 64 | 'POST', 65 | '/' & queueName, 66 | payload 67 | ); 68 | if ( apiResponse.statusCode == 200 ) { 69 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 70 | } 71 | return apiResponse; 72 | } 73 | 74 | /** 75 | * Sends a batch of messages ( up to 10 messages ) 76 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html 77 | * @queueName Required string. The name of the queue to send to (e.g. "123456789/my-sqs-queue"). 78 | * @messages Required array. An array containing messages to post. Maximum 10. 79 | * Each array item must contain a structure that resembles the arguments required by prepareMessage() 80 | */ 81 | public any function sendMessageBatch( 82 | required string queueName, 83 | required array messages 84 | ) { 85 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 86 | var payload = { 'Action': 'SendMessageBatch' }; 87 | if ( arrayLen(arguments.messages) > 10 ){ 88 | throw( type = 'aws.sqs', message = 'Maximum allowed of messages for a batch is 10.' ); 89 | } 90 | for ( var idx = 1; idx <= arrayLen(arguments.messages); idx++ ) { 91 | // add the id per message to declare as a batch job 92 | arguments.messages[idx].batchID = idx; 93 | structAppend( 94 | payload, 95 | prepareMessage( argumentCollection = arguments.messages[idx] ) 96 | ); 97 | } 98 | var apiResponse = apiCall( 99 | requestSettings, 100 | 'POST', 101 | '/' & queueName, 102 | payload 103 | ); 104 | if ( apiResponse.statusCode == 200 ) { 105 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 106 | } 107 | return apiResponse; 108 | } 109 | 110 | /** 111 | * Receives SQS messages 112 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html 113 | * @queueName Required string. The name of the queue to receive messages from (e.g. "123456789/my-sqs-queue"). 114 | * @maxNumberOfMessages Optional numeric. The number of messages to receive from the queue. The mmaxNumberOfMessages is limited to 10. 115 | * @visibilityTimeout Optional numeric. The amount of time until the message will be available in subsequent requests if not deleted. 116 | * Note: When AWS receives more than one message, ReceiveMessageResult is an array. 117 | * When only one message is received, ReceiveMessageResult it is not an array. 118 | * @waitTimeSeconds Optional numeric. The duration (in seconds) for which the call waits for a message to arrive in the queue before returning. 119 | * @attributeNames Optional array. An array of strings for attributes that need to be returned along with each message. ['All'] returns all attributes. 120 | * @messageAttributeNames Optional array. An array of strings for user-defined attributes. Case-sensitive. ['All'] returns all user-defined attributes. 121 | * Example: ['userAttribute1','userAttribute2'] 122 | */ 123 | public any function receiveMessage( 124 | required string queueName, 125 | numeric maxNumberOfMessages = 1, 126 | numeric visibilityTimeout, 127 | numeric waitTimeSeconds, 128 | array attributeNames = [ ], 129 | array messageAttributeNames = [ ] 130 | ) { 131 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 132 | if ( maxNumberOfMessages > 10 ) { 133 | maxNumberOfMessages = 10; 134 | } 135 | var payload = { 'Action': 'ReceiveMessage', 'MaxNumberOfMessages': maxNumberOfMessages }; 136 | if ( structKeyExists( arguments, 'visibilityTimeout' ) && isNumeric( visibilityTimeout ) ) { 137 | payload[ 'VisibilityTimeout' ] = visibilityTimeout; 138 | } 139 | if ( structKeyExists( arguments, 'waitTimeSeconds' ) && isNumeric( waitTimeSeconds ) ) { 140 | payload[ 'WaitTimeSeconds' ] = waitTimeSeconds; 141 | } 142 | for ( var idx = 1; idx <= arrayLen( attributeNames ); idx++ ) { 143 | structAppend( payload, { 'AttributeName.#idx#': attributeNames[ idx ] } ); 144 | } 145 | for ( var idx = 1; idx <= arrayLen( messageAttributeNames ); idx++ ) { 146 | structAppend( payload, { 'MessageAttributeName.#idx#': messageAttributeNames[ idx ] } ); 147 | } 148 | var apiResponse = apiCall( 149 | requestSettings, 150 | 'POST', 151 | '/' & queueName, 152 | payload 153 | ); 154 | if ( apiResponse.statusCode == 200 ) { 155 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 156 | } 157 | return apiResponse; 158 | } 159 | 160 | /** 161 | * Deletes a message 162 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html 163 | * @queueName Required string. The name of the queue (e.g. "123456789/my-sqs-queue"). 164 | * @receiptHandle Required string. Receipt handle of the message to be deleted. This is obtained from receiveMessage response. 165 | */ 166 | public any function deleteMessage( 167 | required string queueName, 168 | required string receiptHandle 169 | ) { 170 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 171 | var apiResponse = apiCall( 172 | requestSettings, 173 | 'POST', 174 | '/' & queueName, 175 | { 'Action': 'DeleteMessage', 'ReceiptHandle': receiptHandle } 176 | ); 177 | if ( apiResponse.statusCode == 200 ) { 178 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 179 | } 180 | return apiResponse; 181 | } 182 | 183 | /** 184 | * Create a queue 185 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html 186 | * @queueName Required string. The name of the queue to create (e.g. "my-sqs-queue"). 187 | * @delaySeconds Optional numeric. The length of time, in seconds, for which the delivery of all messages in the queue is delayed. 188 | * Valid values: An integer from 0 to 900 seconds (15 minutes). Default: 0. 189 | * @messageRetentionPeriod Optional numberic. The length of time, in seconds, for which Amazon SQS retains a message. 190 | * Valid values: An integer from 60 seconds (1 minute) to 1,209,600 seconds (14 days). Default: 345,600 (4 days). 191 | * @receiveMessageWaitTimeSeconds Optional numeric. The length of time, in seconds, for which a ReceiveMessage action waits for a message to arrive. 192 | * Valid values: An integer from 0 to 20 (seconds). Default: 0. 193 | * @visibilityTimeout Optional numeric. The visibility timeout for the queue, in seconds. 194 | * Valid values: An integer from 0 to 43,200 (12 hours). Default: 30. 195 | * @fifoQueue Optional boolean. false will create a standard queue, true will create a FIFO queue. Valid values: true/false. 196 | * @contentBasedDeduplication Enables content-based deduplication. Only applies for FIFO queues. 197 | */ 198 | public any function createQueue( 199 | required string queueName, 200 | numeric delaySeconds = 0, 201 | numeric messageRetentionPeriod = 345600, 202 | numeric receiveMessageWaitTimeSeconds = 0, 203 | numeric visibilityTimeout = 30, 204 | boolean fifoQueue = false, 205 | boolean contentBasedDeduplication = false 206 | ) { 207 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 208 | // Append .fifo suffix for fifo queues as requied by AWS 209 | if ( fifoQueue && right( queueName, 5 ) NEQ '.fifo' ) { 210 | queueName = queueName & '.fifo'; 211 | } 212 | var payload = { 213 | 'Action': 'CreateQueue', 214 | 'QueueName': queueName, 215 | 'Attribute.1.Name': 'DelaySeconds', 216 | 'Attribute.1.Value': delaySeconds, 217 | 'Attribute.2.Name': 'MessageRetentionPeriod', 218 | 'Attribute.2.Value': messageRetentionPeriod, 219 | 'Attribute.3.Name': 'ReceiveMessageWaitTimeSeconds', 220 | 'Attribute.3.Value': receiveMessageWaitTimeSeconds, 221 | 'Attribute.4.Name': 'VisibilityTimeout', 222 | 'Attribute.4.Value': visibilityTimeout 223 | }; 224 | // Only append fifo attributes for fifo queues 225 | if ( fifoQueue ) { 226 | structAppend( 227 | payload, 228 | { 229 | 'Attribute.5.Name': 'FifoQueue', 230 | 'Attribute.5.Value': fifoQueue, 231 | 'Attribute.6.Name': 'ContentBasedDeduplication', 232 | 'Attribute.6.Value': contentBasedDeduplication 233 | } 234 | ); 235 | } 236 | var apiResponse = apiCall( requestSettings, 'POST', '/', payload ); 237 | if ( apiResponse.statusCode == 200 ) { 238 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 239 | } 240 | return apiResponse; 241 | } 242 | 243 | /** 244 | * Delete a queue 245 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteQueue.html 246 | * @queueName Required string. The name of the queue to delete (e.g. "123456789/my-sqs-queue"). 247 | */ 248 | public any function deleteQueue( 249 | required string queueName 250 | ) { 251 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 252 | var apiResponse = apiCall( 253 | requestSettings, 254 | 'POST', 255 | '/' & queueName, 256 | { 'Action': 'DeleteQueue', 'QueueName': queueName } 257 | ); 258 | if ( apiResponse.statusCode == 200 ) { 259 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 260 | } 261 | return apiResponse; 262 | } 263 | 264 | /** 265 | * Purge all messages in queue 266 | * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_PurgeQueue.html 267 | * @queueName Required string. The name of the queue to purge (e.g. "123456789/my-sqs-queue"). 268 | */ 269 | public any function purgeQueue( 270 | required string queueName 271 | ) { 272 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 273 | var apiResponse = apiCall( 274 | requestSettings, 275 | 'POST', 276 | '/' & queueName, 277 | { 'Action': 'PurgeQueue' } 278 | ); 279 | if ( apiResponse.statusCode == 200 ) { 280 | apiResponse[ 'data' ] = utils.parseXmlDocument( apiResponse.rawData ); 281 | } 282 | return apiResponse; 283 | } 284 | 285 | // private 286 | 287 | /** 288 | * @message Required string. The message to post, text format. 289 | * @delaySeconds Optional numeric. The length of time, in seconds, for which to delay a specific message. 290 | * Valid values: 0 to 900. Maximum: 15 minutes. Messages with a positive DelaySeconds value become available for 291 | * processing after the delay period is finished. If you don't specify a value, the default value for the queue applies. 292 | * Note: When you set FifoQueue, you can't set DelaySeconds per message. You can set this parameter only on a queue level. 293 | * @messageAttributes Optional array. An array of message attributes to be added to the message. Each array item must contain a structure 294 | * containing 3 keys: Name, Value, DataType. String and Number are supported DataType values. 295 | * Example: [{'Name':'AttName','Value':'AttVal','DataType':'String'},{'Name':'AttName3','Value':34,'DataType':'Number'}] 296 | * @messageDeduplicationId Optional string. This parameter applies only to FIFO (first-in-first-out) queues. 297 | * The token used for deduplication of sent messages. 298 | * The maximum length of MessageDeduplicationId is 128 characters. MessageDeduplicationId can contain alphanumeric 299 | * characters (a-z, A-Z, 0-9) and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 300 | * @messageGroupId Optional string. This parameter applies only to FIFO (first-in-first-out) queues. 301 | * Note: MessageGroupId is required for FIFO queues. You can't use it for Standard queues. 302 | * The maximum length of MessageGroupId is 128 characters. messageGroupId can contain alphanumeric 303 | * characters (a-z, A-Z, 0-9) and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~). 304 | * @batchID Optional numeric. This is used for batch jobs, if sent, it will prepend SendMessageBatchRequestEntry.{{id}}. to each key create the required Id key 305 | */ 306 | private struct function prepareMessage( 307 | required string message, 308 | numeric delaySeconds, 309 | array messageAttributes = [ ], 310 | string messageDeduplicationId, 311 | string messageGroupId, 312 | numeric batchID 313 | ){ 314 | var isBatch = structKeyExists( arguments, 'batchID' ) && isNumeric( batchID ); 315 | var batchKey = isBatch ? 'SendMessageBatchRequestEntry.#arguments.batchID#.' : ''; 316 | var payload = { '#batchKey#MessageBody': message }; 317 | if ( isBatch ) { 318 | payload['#batchKey#Id'] = arguments.batchID; 319 | } 320 | if ( structKeyExists( arguments, 'delaySeconds' ) && isNumeric( delaySeconds ) ) { 321 | structAppend( payload, { '#batchKey#DelaySeconds': delaySeconds } ); 322 | } 323 | for ( var idx = 1; idx <= arrayLen( messageAttributes ); idx++ ) { 324 | structAppend( 325 | payload, 326 | { 327 | '#batchKey#MessageAttribute.#idx#.Name': messageAttributes[ idx ].Name, 328 | '#batchKey#MessageAttribute.#idx#.Value.StringValue': messageAttributes[ idx ].Value, 329 | '#batchKey#MessageAttribute.#idx#.Value.DataType': messageAttributes[ idx ].DataType 330 | } 331 | ); 332 | } 333 | if ( structKeyExists( arguments, 'messageDeduplicationId' ) && len( messageDeduplicationId ) ) { 334 | structAppend( payload, { '#batchKey#MessageDeduplicationId': messageDeduplicationId } ); 335 | } 336 | if ( structKeyExists( arguments, 'messageGroupId' ) && len( messageGroupId ) ) { 337 | structAppend( payload, { '#batchKey#MessageGroupId': messageGroupId } ); 338 | } 339 | return payload; 340 | } 341 | 342 | private string function getHost( 343 | required string region 344 | ) { 345 | return variables.service & '.' & region & '.amazonaws.com'; 346 | } 347 | 348 | private any function apiCall( 349 | required struct requestSettings, 350 | string httpMethod = 'GET', 351 | string path = '/', 352 | struct queryParams = { }, 353 | struct headers = { }, 354 | any payload = '' 355 | ) { 356 | var host = getHost( requestSettings.region ); 357 | structAppend( queryParams, { 'Version': variables.apiVersion }, false ); 358 | 359 | return api.call( 360 | variables.service, 361 | host, 362 | requestSettings.region, 363 | httpMethod, 364 | path, 365 | queryParams, 366 | headers, 367 | payload, 368 | requestSettings.awsCredentials 369 | ); 370 | } 371 | 372 | } 373 | -------------------------------------------------------------------------------- /services/connect.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'connect'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.utils = variables.api.getUtils(); 11 | variables.settings = arguments.settings; 12 | return this; 13 | } 14 | 15 | /** 16 | * Return a list of instances which are in active state, creation-in-progress state, and failed state. 17 | * Instances that aren't successfully created (they are in a failed state) are returned only for 24 hours 18 | * after the CreateInstance API was invoked. 19 | * https://docs.aws.amazon.com/connect/latest/APIReference/API_ListInstances.html 20 | * 21 | * @maxResults The maximum number of results to return per page. Valid Range: Minimum value of 1. Maximum value of 10. 22 | * @nextToken The token for the next set of results. Use the value returned in the previous response in the next request to retrieve the next set of results. 23 | * 24 | * @preview 25 | */ 26 | public any function listInstances( 27 | maxResults = 10, 28 | nextToken 29 | ) { 30 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 31 | var queryParams = { 'maxResults': arguments.maxResults }; 32 | if ( !isNull( arguments.nextToken ) ) { 33 | queryParams[ 'nextToken' ] = arguments.maxResults; 34 | } 35 | var apiResponse = apiCall( 36 | requestSettings = requestSettings, 37 | httpMethod = 'GET', 38 | path = '/instance', 39 | queryParams = queryParams 40 | ); 41 | return apiResponse; 42 | } 43 | 44 | /** 45 | * Describes the specified contact. 46 | * Contact information remains available in Amazon Connect for 24 months, and then it is deleted. 47 | * Only data from November 12, 2021, and later is returned by this API. 48 | * https://docs.aws.amazon.com/connect/latest/APIReference/API_DescribeContact.html 49 | * 50 | * @instanceId The identifier of the Amazon Connect instance. You can find the instance ID in the Amazon Resource Name (ARN) of the instance. 51 | * @contactId The identifier of the contact. 52 | * 53 | * @preview 54 | */ 55 | public any function describeContact( 56 | required string instanceId, 57 | required string contactId 58 | ) { 59 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 60 | var apiResponse = apiCall( 61 | requestSettings = requestSettings, 62 | httpMethod = 'GET', 63 | path = '/contacts/#arguments.instanceId#/#arguments.contactId#' 64 | ); 65 | return apiResponse; 66 | } 67 | 68 | /** 69 | * Assigns the specified routing profile to the specified user. 70 | * https://docs.aws.amazon.com/connect/latest/APIReference/API_UpdateUserRoutingProfile.html 71 | * 72 | * @instanceId The identifier of the Amazon Connect instance. You can find the instance ID in the Amazon Resource Name (ARN) of the instance. 73 | * @userId The identifier of the user account. 74 | * @routingProfileId The identifier of the routing profile for the user. 75 | */ 76 | public any function updateUserRoutingProfile( 77 | required string instanceId, 78 | required string userId, 79 | required string routingProfileId 80 | ) { 81 | return apiCall( 82 | requestSettings = api.resolveRequestSettings( argumentCollection = arguments ), 83 | httpMethod = 'POST', 84 | path = '/users/#arguments.instanceId#/#arguments.userId#/routing-profile', 85 | payload = serializeJSON( { 'RoutingProfileId': arguments.routingProfileId } ) 86 | ); 87 | } 88 | 89 | /** 90 | * Places an outbound call to a contact, and then initiates the flow. 91 | * It performs the actions in the flow that's specified (in ContactFlowId). 92 | * Agents do not initiate the outbound API, which means that they do not dial the contact. 93 | * If the flow places an outbound call to a contact, and then puts the contact in queue, the call is then routed to the agent, like any other inbound case. 94 | * There is a 60-second dialing timeout for this operation. If the call is not connected after 60 seconds, it fails. 95 | * https://docs.aws.amazon.com/connect/latest/APIReference/API_StartOutboundVoiceContact.html 96 | * 97 | * @instanceId The identifier of the Amazon Connect instance. You can find the instance ID in the Amazon Resource Name (ARN) of the instance. 98 | * @contactFlowId The identifier of the flow for the outbound call. 99 | * To see the ContactFlowId in the Amazon Connect console user interface, on the navigation menu go to Routing, Contact Flows. 100 | * Choose the flow. On the flow page, under the name of the flow, choose Show additional flow information. 101 | * The ContactFlowId is the last part of the ARN. 102 | * @destinationPhoneNumber The phone number of the customer, in E.164 format. 103 | * @campaignId (Optional) The campaign identifier of the outbound communication. 104 | * @awaitAnswerMachinePrompt (Optional) Flag to wait for the answering machine prompt. 105 | * @enableAnswerMachineDetection (Optional) The flag to indicate if answer machine detection analysis needs to be performed for a voice call. 106 | * If set to true, TrafficType must be set as CAMPAIGN. 107 | * @queueId (Optional) The queue for the call. If you specify a queue, the phone displayed for caller ID is the phone number specified in the queue. 108 | * If you do not specify a queue, the queue defined in the flow is used. 109 | * If you do not specify a queue, you must specify a source phone number. 110 | * @sourcePhoneNumber (Optional) The phone number associated with the Amazon Connect instance, in E.164 format. 111 | * If you do not specify a source phone number, you must specify a queue. 112 | * @clientToken (Optional) A unique, case-sensitive identifier that you provide to ensure the idempotency of the request. 113 | * If not provided, the AWS SDK populates this field. 114 | * @attributes (Optional) A custom key-value pair using a struct. The attributes are standard Amazon Connect attributes, 115 | * and can be accessed in flows just like any other contact attributes. 116 | * There can be up to 32,768 UTF-8 bytes across all key-value pairs per contact. 117 | * Attribute keys can include only alphanumeric, dash, and underscore characters. 118 | */ 119 | public any function startOutboundVoiceContact( 120 | required string instanceId, 121 | required string contactFlowId, 122 | required string destinationPhoneNumber, 123 | string campaignId, 124 | boolean awaitAnswerMachinePrompt, 125 | boolean enableAnswerMachineDetection, 126 | string queueId, 127 | string sourcePhoneNumber, 128 | string clientToken, 129 | struct attributes = { } 130 | ) { 131 | if ( isNull( arguments.queueId ) && isNull( arguments.sourcePhoneNumber ) ) { 132 | throw( 'Either a queueId or a sourcePhoneNumber must be provided' ); 133 | } 134 | 135 | // Denotes the class of traffic. Calls with different traffic types are handled differently by Amazon Connect. 136 | // The default value is GENERAL. Use CAMPAIGN if `EnableAnswerMachineDetection` is set to true. For all other cases, use GENERAL. 137 | var trafficType = 'GENERAL'; 138 | if ( !isNull( arguments.enableAnswerMachineDetection ) && arguments.enableAnswerMachineDetection ) { 139 | trafficType = 'CAMPAIGN'; 140 | } 141 | 142 | var payload = { 143 | 'InstanceId': arguments.instanceId, 144 | 'ContactFlowId': arguments.contactFlowId, 145 | 'Attributes': arguments.attributes, 146 | 'DestinationPhoneNumber': arguments.destinationPhoneNumber, 147 | 'TrafficType': trafficType 148 | }; 149 | 150 | // Optional Keys 151 | if ( !isNull( arguments.campaignId ) ) { 152 | payload[ 'CampaignId' ] = arguments.campaignId; 153 | } 154 | if ( !isNull( arguments.queueId ) ) { 155 | payload[ 'QueueId' ] = arguments.queueId; 156 | } 157 | if ( !isNull( arguments.sourcePhoneNumber ) ) { 158 | payload[ 'SourcePhoneNumber' ] = arguments.sourcePhoneNumber; 159 | } 160 | if ( !isNull( arguments.clientToken ) ) { 161 | payload[ 'ClientToken' ] = arguments.clientToken; 162 | } 163 | 164 | if ( !isNull( arguments.awaitAnswerMachinePrompt ) || !isNull( arguments.enableAnswerMachineDetection ) ) { 165 | payload[ 'AnswerMachineDetectionConfig' ] = { }; 166 | if ( !isNull( arguments.awaitAnswerMachinePrompt ) ) { 167 | payload[ 'AnswerMachineDetectionConfig' ][ 'AwaitAnswerMachinePrompt' ] = arguments.awaitAnswerMachinePrompt; 168 | } 169 | if ( !isNull( arguments.enableAnswerMachineDetection ) ) { 170 | payload[ 'AnswerMachineDetectionConfig' ][ 'EnableAnswerMachineDetection' ] = arguments.enableAnswerMachineDetection; 171 | } 172 | } 173 | 174 | return apiCall( 175 | requestSettings = api.resolveRequestSettings( argumentCollection = arguments ), 176 | httpMethod = 'PUT', 177 | path = '/contact/outbound-voice', 178 | payload = serializeJSON( payload ) 179 | ); 180 | } 181 | 182 | /** 183 | * Creates a user account for the specified Amazon Connect instance. 184 | * 185 | * @instanceId The identifier of the Amazon Connect instance. You can find the instance ID in the Amazon Resource Name (ARN) of the instance. 186 | * @routingProfileId The identifier of the routing profile for the user. 187 | * @securityProfileIds The identifier of the security profile for the user. 188 | * @username The user name for the account. For instances not using SAML for identity management, the user name can include up to 20 characters. 189 | * If you are using SAML for identity management, the user name can include up to 64 characters from [a-zA-Z0-9_-.\@]+. 190 | * @phoneType The phone type. Valid values are: `SOFT_PHONE` and `DESK_PHONE` 191 | * @password (Optional) The password for the user account. A password is required if you are using Amazon Connect for identity management. 192 | * Otherwise, it is an error to include a password. 193 | * @afterContactWorkTimeLimit (Optional) The After Call Work (ACW) timeout setting, in seconds. 194 | * @autoAccept (Optional) The Auto accept setting. 195 | * @deskPhoneNumber (Optional) The phone number for the user's desk phone. 196 | * @directoryUserId (Optional) The identifier of the user account in the directory used for identity management. If Amazon Connect cannot access the directory, you can specify this identifier to authenticate users. 197 | * If you include the identifier, we assume that Amazon Connect cannot access the directory. Otherwise, the identity information is used to authenticate users from your directory. 198 | * This parameter is required if you are using an existing directory for identity management in Amazon Connect when Amazon Connect cannot access your directory to authenticate users. 199 | * If you are using SAML for identity management and include this parameter, an error is returned. 200 | * @hierarchyGroupId (Optional) The identifier of the hierarchy group for the user. 201 | * @firstName (Optional) The first name. This is required if you are using Amazon Connect or SAML for identity management. 202 | * @lastName (Optional) The last name. This is required if you are using Amazon Connect or SAML for identity management. 203 | * @mobileNumber (Optional) The user's mobile number. 204 | * @email (Optional) The email address. If you are using SAML for identity management and include this parameter, an error is returned. 205 | * @secondaryEmail (Optional) The user's secondary email address. If you provide a secondary email, the user receives email notifications - other than password reset notifications - to this email address instead of to their primary email address. 206 | * @tags (Optional) The tags used to organize, track, or control access for this resource. For example, { "tags": {"key1":"value1", "key2":"value2"} }. 207 | */ 208 | public any function createUser( 209 | required string instanceId, 210 | required string routingProfileId, 211 | required array securityProfileIds, 212 | required string username, 213 | string phoneType = 'SOFT_PHONE', 214 | string password, 215 | numeric afterContactWorkTimeLimit, 216 | boolean autoAccept, 217 | string deskPhoneNumber, 218 | string directoryUserId, 219 | string hierarchyGroupId, 220 | string firstName, 221 | string lastName, 222 | string mobileNumber, 223 | string email, 224 | string secondaryEmail, 225 | struct tags = { } 226 | ) { 227 | var payload = { 228 | 'RoutingProfileId': arguments.routingProfileId, 229 | 'SecurityProfileIds': arguments.securityProfileIds, 230 | 'Username': arguments.username, 231 | 'PhoneConfig': { 'PhoneType': arguments.phoneType }, 232 | 'Tags': arguments.tags 233 | }; 234 | 235 | if ( !isNull( arguments.password ) ) { 236 | payload[ 'Password' ] = arguments.password; 237 | } 238 | 239 | if ( !isNull( arguments.directoryUserId ) ) { 240 | payload[ 'DirectoryUserId' ] = arguments.directoryUserId; 241 | } 242 | 243 | if ( !isNull( arguments.hierarchyGroupId ) ) { 244 | payload[ 'HierarchyGroupId' ] = arguments.hierarchyGroupId; 245 | } 246 | 247 | if ( !isNull( arguments.afterContactWorkTimeLimit ) ) { 248 | payload[ 'PhoneConfig' ][ 'AfterContactWorkTimeLimit' ] = arguments.afterContactWorkTimeLimit; 249 | } 250 | 251 | if ( !isNull( arguments.autoAccept ) ) { 252 | payload[ 'PhoneConfig' ][ 'AutoAccept' ] = arguments.autoAccept; 253 | } 254 | 255 | if ( !isNull( arguments.deskPhoneNumber ) ) { 256 | payload[ 'PhoneConfig' ][ 'DeskPhoneNumber' ] = arguments.deskPhoneNumber; 257 | } 258 | 259 | if ( !isNull( arguments.firstName ) ) { 260 | if ( !structKeyExists( payload, 'IdentityInfo' ) ) { 261 | payload[ 'IdentityInfo' ] = { }; 262 | } 263 | payload[ 'IdentityInfo' ][ 'FirstName' ] = arguments.firstName; 264 | } 265 | 266 | if ( !isNull( arguments.lastName ) ) { 267 | if ( !structKeyExists( payload, 'IdentityInfo' ) ) { 268 | payload[ 'IdentityInfo' ] = { }; 269 | } 270 | payload[ 'IdentityInfo' ][ 'LastName' ] = arguments.lastName; 271 | } 272 | 273 | if ( !isNull( arguments.mobileNumber ) ) { 274 | if ( !structKeyExists( payload, 'IdentityInfo' ) ) { 275 | payload[ 'IdentityInfo' ] = { }; 276 | } 277 | payload[ 'IdentityInfo' ][ 'Mobile' ] = arguments.mobileNumber; 278 | } 279 | 280 | if ( !isNull( arguments.email ) ) { 281 | if ( !structKeyExists( payload, 'IdentityInfo' ) ) { 282 | payload[ 'IdentityInfo' ] = { }; 283 | } 284 | payload[ 'IdentityInfo' ][ 'Email' ] = arguments.email; 285 | } 286 | 287 | if ( !isNull( arguments.secondaryEmail ) ) { 288 | if ( !structKeyExists( payload, 'IdentityInfo' ) ) { 289 | payload[ 'IdentityInfo' ] = { }; 290 | } 291 | payload[ 'IdentityInfo' ][ 'SecondaryEmail' ] = arguments.secondaryEmail; 292 | } 293 | 294 | return apiCall( 295 | requestSettings = api.resolveRequestSettings( argumentCollection = arguments ), 296 | httpMethod = 'PUT', 297 | path = '/users/#arguments.instanceId#', 298 | payload = serializeJSON( payload ) 299 | ); 300 | } 301 | 302 | /** 303 | * Changes the current status of a user or agent in Amazon Connect. If the agent is currently handling a contact, this sets the agent's next status. 304 | * https://docs.aws.amazon.com/connect/latest/APIReference/API_PutUserStatus.html 305 | * 306 | * @instanceId The identifier of the Amazon Connect instance. You can find the instance ID in the Amazon Resource Name (ARN) of the instance. 307 | * @userId The identifier of the user account. 308 | * @agentStatusId The identifier of the agent status. 309 | */ 310 | public any function putUserStatus( 311 | required string instanceId, 312 | required string userId, 313 | required string agentStatusId 314 | ) { 315 | return apiCall( 316 | requestSettings = api.resolveRequestSettings( argumentCollection = arguments ), 317 | httpMethod = 'PUT', 318 | path = '/users/#arguments.instanceId#/#arguments.userId#/status', 319 | payload = serializeJSON( { 'AgentStatusId': arguments.agentStatusId } ) 320 | ); 321 | } 322 | 323 | /** 324 | * Updates the phone configuration settings for the specified user. 325 | * https://docs.aws.amazon.com/connect/latest/APIReference/API_UpdateUserPhoneConfig.html 326 | * 327 | * @instanceId The identifier of the Amazon Connect instance. You can find the instance ID in the Amazon Resource Name (ARN) of the instance. 328 | * @userId The identifier of the user account. 329 | * @phoneType The phone type. Valid values are: `SOFT_PHONE` and `DESK_PHONE` 330 | * @afterContactWorkTimeLimit The After Call Work (ACW) timeout setting, in seconds. Minimum value of 0. 331 | * @autoAccept The auto accept setting for having the agent auto accept incoming calls routed to them. 332 | * @deskPhoneNumber The phone number for the user's desk phone. 333 | */ 334 | public any function updateUserPhoneConfig( 335 | required string instanceId, 336 | required string userId, 337 | string phoneType = 'SOFT_PHONE', 338 | numeric afterContactWorkTimeLimit, 339 | boolean autoAccept, 340 | string deskPhoneNumber 341 | ) { 342 | var phoneConfig = { 'PhoneType': arguments.phoneType }; 343 | if ( !isNull( arguments.afterContactWorkTimeLimit ) ) { 344 | phoneConfig[ 'AfterContactWorkTimeLimit' ] = arguments.afterContactWorkTimeLimit; 345 | } 346 | if ( !isNull( arguments.autoAccept ) ) { 347 | phoneConfig[ 'AutoAccept' ] = arguments.autoAccept; 348 | } 349 | if ( !isNull( arguments.deskPhoneNumber ) ) { 350 | phoneConfig[ 'DeskPhoneNumber' ] = arguments.deskPhoneNumber; 351 | } 352 | 353 | return apiCall( 354 | requestSettings = api.resolveRequestSettings( argumentCollection = arguments ), 355 | httpMethod = 'POST', 356 | path = '/users/#arguments.instanceId#/#arguments.userId#/phone-config', 357 | payload = serializeJSON( { 'PhoneConfig': phoneConfig } ) 358 | ); 359 | } 360 | 361 | private any function apiCall( 362 | required struct requestSettings, 363 | string httpMethod = 'GET', 364 | string path = '/', 365 | struct queryParams = { }, 366 | struct headers = { }, 367 | any payload = '' 368 | ) { 369 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 370 | if ( !structKeyExists( headers, 'Content-Type' ) ) { 371 | headers[ 'Content-Type' ] = 'application/json'; 372 | } 373 | var useSSL = !structKeyExists( variables.settings, 'useSSL' ) || variables.settings.useSSL; 374 | var apiResponse = api.call( 375 | variables.service, 376 | host, 377 | requestSettings.region, 378 | httpMethod, 379 | path, 380 | queryParams, 381 | headers, 382 | payload, 383 | requestSettings.awsCredentials, 384 | false, 385 | useSSL 386 | ); 387 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 388 | return apiResponse; 389 | } 390 | 391 | } 392 | -------------------------------------------------------------------------------- /services/personalize.cfc: -------------------------------------------------------------------------------- 1 | component { 2 | 3 | variables.service = 'personalize'; 4 | 5 | public any function init( 6 | required any api, 7 | required struct settings 8 | ) { 9 | variables.api = arguments.api; 10 | variables.apiVersion = arguments.settings.apiVersion; 11 | return this; 12 | } 13 | 14 | /** 15 | * Creates a campaign by deploying a solution version. When a client calls the GetRecommendations and GetPersonalizedRanking APIs, a campaign is specified in the request. 16 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateCampaign.html 17 | * @minProvisionedTPS required numeric. Specifies the requested minimum provisioned transactions (recommendations) per second that Amazon Personalize will support. 18 | * @name required string. A name for the new campaign. The campaign name must be unique within your account. 19 | * @solutionVersionArn required string. The Amazon Resource Name (ARN) of the solution version to deploy. 20 | */ 21 | public any function createCampaign( 22 | required numeric minProvisionedTPS, 23 | required string name, 24 | required string solutionVersionArn 25 | ) { 26 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 27 | var args = { 28 | 'minProvisionedTPS': arguments.minProvisionedTPS, 29 | 'name': arguments.name, 30 | 'solutionVersionArn': arguments.solutionVersionArn 31 | }; 32 | 33 | return apiCall( requestSettings, 'CreateCampaign', args ); 34 | } 35 | 36 | /** 37 | * Creates an empty dataset and adds it to the specified dataset group. Use CreateDatasetImportJob to import your training data to a dataset. 38 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateDataset.html 39 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group to add the dataset to. 40 | * @datasetType required string. The type of dataset. One of the following (case insensitive) values: Interactions Items Users 41 | * @name required string. The name for the dataset. 42 | * @schemaArn required string. The ARN of the schema to associate with the dataset. The schema defines the dataset fields. 43 | */ 44 | public any function createDataset( 45 | required string datasetGroupArn, 46 | required string datasetType, 47 | required string name, 48 | required string schemaArn 49 | ) { 50 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 51 | var args = { 52 | 'datasetGroupArn': arguments.datasetGroupArn, 53 | 'datasetType': arguments.datasetType, 54 | 'name': arguments.name, 55 | 'schemaArn': arguments.schemaArn 56 | }; 57 | 58 | return apiCall( requestSettings, 'CreateDataset', args ); 59 | } 60 | 61 | /** 62 | * Creates an empty dataset group. A dataset group contains related datasets that supply data for training a model. A dataset group can contain at most three datasets, one for each type of dataset: Interactions Items Users 63 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateDatasetGroup.html 64 | * @name required string. The name for the dataset. 65 | * @kmsKeyArn optional string. The Amazon Resource Name (ARN) of a KMS key used to encrypt the datasets. 66 | * @roleArn optional string. The ARN of the IAM role that has permissions to access the KMS key. Supplying an IAM role is only valid when also specifying a KMS key. 67 | */ 68 | public any function createDatasetGroup( 69 | required string name, 70 | string kmsKeyArn, 71 | string roleArn 72 | ) { 73 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 74 | var args = { 'name': arguments.name }; 75 | if ( !isNull( arguments.kmsKeyArn ) ) args[ 'kmsKeyArn' ] = arguments.kmsKeyArn; 76 | if ( !isNull( arguments.roleArn ) ) args[ 'roleArn' ] = arguments.roleArn; 77 | 78 | return apiCall( requestSettings, 'CreateDatasetGroup', args ); 79 | } 80 | 81 | /** 82 | * Creates a job that imports training data from your data source (an Amazon S3 bucket) to an Amazon Personalize dataset. To allow Amazon Personalize to import the training data, you must specify an AWS Identity and Access Management (IAM) role that has permission to read from the data source. 83 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateDatasetImportJob.html 84 | * @datasetArn required string. The ARN of the dataset that receives the imported data. 85 | * @dataLocation required string. The path to the Amazon S3 bucket where the data that you want to upload to your dataset is stored. 86 | * @jobName required string. The name for the dataset import job. 87 | * @roleArn required string. The ARN of the IAM role that has permissions to read from the Amazon S3 data source. 88 | */ 89 | public any function createDatasetImportJob( 90 | required string datasetArn, 91 | required string dataLocation, 92 | required string jobName, 93 | required string roleArn 94 | ) { 95 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 96 | var args = { 97 | 'jobName': arguments.jobName, 98 | 'datasetArn': arguments.datasetArn, 99 | 'dataSource': { 'dataLocation': arguments.dataLocation }, 100 | 'roleArn': arguments.roleArn 101 | }; 102 | 103 | return apiCall( requestSettings, 'CreateDatasetImportJob', args ); 104 | } 105 | 106 | /** 107 | * Creates an event tracker that you use when sending event data to the specified dataset group using the PutEvents API. 108 | When Amazon Personalize creates an event tracker, it also creates an event-interactions dataset in the dataset group associated with the event tracker. 109 | The event-interactions dataset stores the event data from the PutEvents call. The contents of this dataset are not available to the user. 110 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateEventTracker.html 111 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group that receives the event data. 112 | * @name required string. The name for the event tracker. 113 | */ 114 | public any function createEventTracker( 115 | required string datasetGroupArn, 116 | required string name 117 | ) { 118 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 119 | var args = { 'name': arguments.name, 'datasetGroupArn': arguments.datasetGroupArn }; 120 | 121 | return apiCall( requestSettings, 'CreateEventTracker', args ); 122 | } 123 | 124 | /** 125 | * Creates an Amazon Personalize schema from the specified schema string. The schema you create must be in Avro JSON format. 126 | Amazon Personalize recognizes three schema variants. Each schema is associated with a dataset type and has a set of required field and keywords. You specify a schema when you call CreateDataset. 127 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateSchema.html 128 | * @name required string. The name for the schema. 129 | * @schema required string. A schema in Avro JSON format. 130 | */ 131 | public any function createSchema( 132 | required string name, 133 | required string schema 134 | ) { 135 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 136 | var args = { 'name': arguments.name, 'schema': arguments.schema }; 137 | 138 | return apiCall( requestSettings, 'CreateSchema', args ); 139 | } 140 | 141 | /** 142 | * Creates the configuration for training a model. A trained model is known as a solution. After the configuration is created, you train the model (create a solution) by calling the CreateSolutionVersion operation. 143 | Every time you call CreateSolutionVersion, a new version of the solution is created. 144 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateSolution.html 145 | * @name required string. The name for the solution. 146 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group that provides the training data. 147 | * @eventType optional string. When you have multiple event types (using an EVENT_TYPE schema field), this parameter specifies which event type (for example, 'click' or 'like') is used for training the model. 148 | * @performAutoML optional boolean. Whether to perform automated machine learning (AutoML). The default is false. For this case, you must specify recipeArn. 149 | When set to true, Amazon Personalize analyzes your training data and selects the optimal USER_PERSONALIZATION recipe and hyperparameters. In this case, you must omit recipeArn. 150 | Amazon Personalize determines the optimal recipe by running tests with different values for the hyperparameters. AutoML lengthens the training process as compared to selecting a specific recipe. 151 | * @performHPO optional boolean. Whether to perform hyperparameter optimization (HPO) on the specified or selected recipe. The default is false. 152 | When performing AutoML, this parameter is always true and you should not set it to false. 153 | * @recipeArn optional string. The ARN of the recipe to use for model training. Only specified when performAutoML is false. 154 | * @solutionConfig optional struct. The configuration to use with the solution, see https://docs.aws.amazon.com/personalize/latest/dg/API_SolutionConfig.html for key/data format. 155 | When performAutoML is set to true, Amazon Personalize only evaluates the autoMLConfig section of the solution configuration. 156 | */ 157 | public any function createSolution( 158 | required string name, 159 | required string datasetGroupArn, 160 | string eventType, 161 | boolean performAutoML, 162 | boolean performHPO, 163 | string recipeArn, 164 | struct solutionConfig 165 | ) { 166 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 167 | var args = { 'name': arguments.name, 'datasetGroupArn': arguments.datasetGroupArn }; 168 | if ( !isNull( arguments.eventType ) ) args[ 'eventType' ] = arguments.eventType; 169 | if ( !isNull( arguments.performAutoML ) ) args[ 'performAutoML' ] = arguments.performAutoML; 170 | if ( !isNull( arguments.performHPO ) ) args[ 'performHPO' ] = arguments.performHPO; 171 | if ( !isNull( arguments.recipeArn ) ) args[ 'recipeArn' ] = arguments.recipeArn; 172 | if ( !isNull( arguments.solutionConfig ) ) args[ 'solutionConfig' ] = arguments.solutionConfig; 173 | 174 | return apiCall( requestSettings, 'CreateSolution', args ); 175 | } 176 | 177 | /** 178 | * Trains or retrains an active solution. A solution is created using the CreateSolution operation and must be in the ACTIVE state before calling CreateSolutionVersion. A new version of the solution is created every time you call this operation. 179 | * https://docs.aws.amazon.com/personalize/latest/dg/API_CreateSolutionVersion.html 180 | * @solutionArn required string. The Amazon Resource Name (ARN) of the solution to retrain. 181 | */ 182 | public any function createSolutionVersion( 183 | required string solutionArn 184 | ) { 185 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 186 | var args = { 'solutionArn': arguments.solutionArn }; 187 | 188 | return apiCall( requestSettings, 'CreateSolutionVersion', args ); 189 | } 190 | 191 | /** 192 | * Removes a campaign by deleting the solution deployment. The solution that the campaign is based on is not deleted and can be redeployed when needed. A deleted campaign can no longer be specified in a GetRecommendations request. For more information on campaigns, see CreateCampaign. 193 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DeleteCampaign.html 194 | * @campaignArn required string. The Amazon Resource Name (ARN) of the campaign to delete. 195 | */ 196 | public any function deleteCampaign( 197 | required string campaignArn 198 | ) { 199 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 200 | var args = { 'campaignArn': arguments.campaignArn }; 201 | 202 | return apiCall( requestSettings, 'DeleteCampaign', args ); 203 | } 204 | 205 | /** 206 | * Deletes a dataset. You can't delete a dataset if an associated DatasetImportJob or SolutionVersion is in the CREATE PENDING or IN PROGRESS state. For more information on datasets, see CreateDataset. 207 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DeleteDataset.html 208 | * @datasetArn required string. The Amazon Resource Name (ARN) of the dataset to delete. 209 | */ 210 | public any function deleteDataset( 211 | required string datasetArn 212 | ) { 213 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 214 | var args = { 'datasetArn': arguments.datasetArn }; 215 | 216 | return apiCall( requestSettings, 'DeleteDataset', args ); 217 | } 218 | 219 | /** 220 | * Deletes a dataset group. Before you delete a dataset group, you must delete the following: 221 | All associated event trackers. 222 | All associated solutions. 223 | All datasets in the dataset group. 224 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DeleteDatasetGroup.html 225 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group to delete. 226 | */ 227 | public any function deleteDatasetGroup( 228 | required string datasetGroupArn 229 | ) { 230 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 231 | var args = { 'datasetGroupArn': arguments.datasetGroupArn }; 232 | 233 | return apiCall( requestSettings, 'DeleteDatasetGroup', args ); 234 | } 235 | 236 | /** 237 | * Deletes the event tracker. Does not delete the event-interactions dataset from the associated dataset group. For more information on event trackers, see CreateEventTracker. 238 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DeleteEventTracker.html 239 | * @eventTrackerArn required string. The Amazon Resource Name (ARN) of the event tracker to delete. 240 | */ 241 | public any function deleteEventTracker( 242 | required string eventTrackerArn 243 | ) { 244 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 245 | var args = { 'eventTrackerArn': arguments.eventTrackerArn }; 246 | 247 | return apiCall( requestSettings, 'DeleteEventTracker', args ); 248 | } 249 | 250 | /** 251 | * Deletes a schema. Before deleting a schema, you must delete all datasets referencing the schema. For more information on schemas, see CreateSchema. 252 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DeleteSchema.html 253 | * @schemaArn required string. The Amazon Resource Name (ARN) of the schema to delete. 254 | */ 255 | public any function deleteSchema( 256 | required string schemaArn 257 | ) { 258 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 259 | var args = { 'schemaArn': arguments.schemaArn }; 260 | 261 | return apiCall( requestSettings, 'DeleteSchema', args ); 262 | } 263 | 264 | /** 265 | * Deletes all versions of a solution and the Solution object itself. Before deleting a solution, you must delete all campaigns based on the solution. 266 | To determine what campaigns are using the solution, call ListCampaigns and supply the Amazon Resource Name (ARN) of the solution. 267 | You can't delete a solution if an associated SolutionVersion is in the CREATE PENDING or IN PROGRESS state. 268 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DeleteSolution.html 269 | * @solutionArn required string. The Amazon Resource Name (ARN) of the solution to delete. 270 | */ 271 | public any function deleteSolution( 272 | required string solutionArn 273 | ) { 274 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 275 | var args = { 'solutionArn': arguments.solutionArn }; 276 | 277 | return apiCall( requestSettings, 'DeleteSolution', args ); 278 | } 279 | 280 | /** 281 | * Describes the given algorithm. 282 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeAlgorithm.html 283 | * @algorithmArn required string. The Amazon Resource Name (ARN) of the algorithm to describe. 284 | */ 285 | public any function describeAlgorithm( 286 | required string algorithmArn 287 | ) { 288 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 289 | var args = { 'algorithmArn': arguments.algorithmArn }; 290 | 291 | return apiCall( requestSettings, 'DescribeAlgorithm', args ); 292 | } 293 | 294 | /** 295 | * Describes the given campaign, including its status. 296 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeCampaign.html 297 | * @campaignArn required string. The Amazon Resource Name (ARN) of the campaign. 298 | */ 299 | public any function describeCampaign( 300 | required string campaignArn 301 | ) { 302 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 303 | var args = { 'campaignArn': arguments.campaignArn }; 304 | 305 | return apiCall( requestSettings, 'DescribeCampaign', args ); 306 | } 307 | 308 | /** 309 | * Describes the given dataset. For more information on datasets, see CreateDataset. 310 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeDataset.html 311 | * @datasetArn required string. The Amazon Resource Name (ARN) of the dataset to describe. 312 | */ 313 | public any function describeDataset( 314 | required string datasetArn 315 | ) { 316 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 317 | var args = { 'datasetArn': arguments.datasetArn }; 318 | 319 | return apiCall( requestSettings, 'DescribeDataset', args ); 320 | } 321 | 322 | /** 323 | * Describes the given dataset group. 324 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeDatasetGroup.html 325 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group to describe. 326 | */ 327 | public any function describeDatasetGroup( 328 | required string datasetGroupArn 329 | ) { 330 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 331 | var args = { 'datasetGroupArn': arguments.datasetGroupArn }; 332 | 333 | return apiCall( requestSettings, 'DescribeDatasetGroup', args ); 334 | } 335 | 336 | /** 337 | * Describes the dataset import job created by CreateDatasetImportJob, including the import job status. 338 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeDatasetImportJob.html 339 | * @datasetImportJobArn required string. The Amazon Resource Name (ARN) of the dataset import job to describe. 340 | */ 341 | public any function describeDatasetImportJob( 342 | required string datasetImportJobArn 343 | ) { 344 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 345 | var args = { 'datasetImportJobArn': arguments.datasetImportJobArn }; 346 | 347 | return apiCall( requestSettings, 'DescribeDatasetImportJob', args ); 348 | } 349 | 350 | /** 351 | * Describes an event tracker. The response includes the trackingId and status of the event tracker. For more information on event trackers, see CreateEventTracker. 352 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeEventTracker.html 353 | * @eventTrackerArn required string. The Amazon Resource Name (ARN) of the event tracker to describe. 354 | */ 355 | public any function describeEventTracker( 356 | required string eventTrackerArn 357 | ) { 358 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 359 | var args = { 'eventTrackerArn': arguments.eventTrackerArn }; 360 | 361 | return apiCall( requestSettings, 'DescribeEventTracker', args ); 362 | } 363 | 364 | /** 365 | * Describes the given feature transformation. 366 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeFeatureTransformation.html 367 | * @featureTransformationArn required string. The Amazon Resource Name (ARN) of the feature transformation to describe. 368 | */ 369 | public any function describeFeatureTransformation( 370 | required string featureTransformationArn 371 | ) { 372 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 373 | var args = { 'featureTransformationArn': arguments.featureTransformationArn }; 374 | 375 | return apiCall( requestSettings, 'DescribeFeatureTransformation', args ); 376 | } 377 | 378 | /** 379 | * Describes a recipe. A recipe contains three items: 380 | - An algorithm that trains a model. 381 | - Hyperparameters that govern the training. 382 | - Feature transformation information for modifying the input data before training. 383 | Amazon Personalize provides a set of predefined recipes. You specify a recipe when you create a solution with the CreateSolution API. 384 | CreateSolution trains a model by using the algorithm in the specified recipe and a training dataset. 385 | The solution, when deployed as a campaign, can provide recommendations using the GetRecommendations API. 386 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeRecipe.html 387 | * @recipeArn required string. The Amazon Resource Name (ARN) of the feature transformation to describe. 388 | */ 389 | public any function describeRecipe( 390 | required string recipeArn 391 | ) { 392 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 393 | var args = { 'recipeArn': arguments.recipeArn }; 394 | 395 | return apiCall( requestSettings, 'DescribeRecipe', args ); 396 | } 397 | 398 | /** 399 | * Describes a schema. For more information on schemas, see CreateSchema. 400 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeSchema.html 401 | * @schemaArn required string. The Amazon Resource Name (ARN) of the schema to retrieve. 402 | */ 403 | public any function describeSchema( 404 | required string schemaArn 405 | ) { 406 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 407 | var args = { 'schemaArn': arguments.schemaArn }; 408 | 409 | return apiCall( requestSettings, 'DescribeSchema', args ); 410 | } 411 | 412 | /** 413 | * Describes a solution. For more information on solutions, see CreateSolution. 414 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeSolution.html 415 | * @solutionArn required string. The Amazon Resource Name (ARN) of the solution to describe. 416 | */ 417 | public any function describeSolution( 418 | required string solutionArn 419 | ) { 420 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 421 | var args = { 'solutionArn': arguments.solutionArn }; 422 | 423 | return apiCall( requestSettings, 'DescribeSolution', args ); 424 | } 425 | 426 | /** 427 | * Describes a specific version of a solution. For more information on solutions, see CreateSolution. 428 | * https://docs.aws.amazon.com/personalize/latest/dg/API_DescribeSolutionVersion.html 429 | * @solutionVersionArn required string. The Amazon Resource Name (ARN) of the solution version. 430 | */ 431 | public any function describeSolutionVersion( 432 | required string solutionVersionArn 433 | ) { 434 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 435 | var args = { 'solutionVersionArn': arguments.solutionVersionArn }; 436 | 437 | return apiCall( requestSettings, 'DescribeSolutionVersion', args ); 438 | } 439 | 440 | /** 441 | * Gets the metrics for the specified solution version. 442 | * https://docs.aws.amazon.com/personalize/latest/dg/API_GetSolutionMetrics.html 443 | * @solutionVersionArn a string: The Amazon Resource Name (ARN) of the solution version. 444 | */ 445 | public any function getSolutionMetrics( 446 | required string solutionVersionArn 447 | ) { 448 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 449 | var args = { 'solutionVersionArn': arguments.solutionVersionArn }; 450 | 451 | return apiCall( requestSettings, 'GetSolutionMetrics', args ); 452 | } 453 | 454 | /** 455 | * Returns a list of campaigns that use the given solution. When a solution is not specified, all the campaigns associated with the account are listed. The response provides the properties for each campaign, including the Amazon Resource Name (ARN). For more information on campaigns, see CreateCampaign. 456 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListCampaigns.html 457 | * @solutionArn a string: The Amazon Resource Name (ARN) of the solution to list the campaigns for. When a solution is not specified, all the campaigns associated with the account are listed. 458 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 459 | * @nextToken Optional string. A token returned from the previous call to ListCampaigns for getting the next set of campaigns (if they exist). 460 | */ 461 | public any function listCampaigns( 462 | string solutionArn, 463 | numeric maxResults, 464 | string nextToken 465 | ) { 466 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 467 | var args = { }; 468 | if ( !isNull( arguments.solutionArn ) ) args[ 'solutionArn' ] = arguments.solutionArn; 469 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 470 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 471 | 472 | return apiCall( requestSettings, 'ListCampaigns', args ); 473 | } 474 | 475 | /** 476 | * Returns a list of dataset groups. The response provides the properties for each dataset group, including the Amazon Resource Name (ARN). 477 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListDatasetGroups.html 478 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 479 | * @nextToken Optional string. A token returned from the previous call to listDatasetGroups for getting the next set of solutions (if they exist). 480 | */ 481 | public any function listDatasetGroups( 482 | numeric maxResults, 483 | string nextToken 484 | ) { 485 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 486 | var args = { }; 487 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 488 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 489 | 490 | return apiCall( requestSettings, 'ListDatasetGroups', args ); 491 | } 492 | 493 | /** 494 | * Returns a list of dataset import jobs that use the given dataset. When a dataset is not specified, all the dataset import jobs associated with the account are listed. 495 | The response provides the properties for each dataset import job, including the Amazon Resource Name (ARN). 496 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListDatasetImportJobs.html 497 | * @datasetArn required string. The Amazon Resource Name (ARN) of the dataset to list the dataset import jobs for. 498 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 499 | * @nextToken Optional string. A token returned from the previous call to ListDatasetImportJobs for getting the next set of dataset import jobs (if they exist). 500 | */ 501 | public any function listDatasetImportJobs( 502 | required string datasetArn, 503 | numeric maxResults, 504 | string nextToken 505 | ) { 506 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 507 | var args = { 'datasetArn': arguments.datasetArn }; 508 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 509 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 510 | 511 | return apiCall( requestSettings, 'ListDatasetImportJobs', args ); 512 | } 513 | 514 | /** 515 | * Returns the list of datasets contained in the given dataset group. The response provides the properties for each dataset, including the Amazon Resource Name (ARN). 516 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListDatasets.html 517 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group to list the datasets for. 518 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 519 | * @nextToken Optional string. A token returned from the previous call to ListDatasets for getting the next set of datasets (if they exist). 520 | */ 521 | public any function listDatasets( 522 | required string datasetGroupArn, 523 | numeric maxResults, 524 | string nextToken 525 | ) { 526 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 527 | var args = { 'datasetGroupArn': arguments.datasetGroupArn }; 528 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 529 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 530 | 531 | return apiCall( requestSettings, 'ListDatasets', args ); 532 | } 533 | 534 | /** 535 | * Returns the list of event trackers associated with the account. The response provides the properties for each event tracker, including the Amazon Resource Name (ARN) and tracking ID. 536 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListEventTrackers.html 537 | * @datasetGroupArn required string. The Amazon Resource Name (ARN) of the dataset group to list the datasets for. 538 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 539 | * @nextToken Optional string. A token returned from the previous call to ListEventTrackers for getting the next set of event trackers (if they exist). 540 | */ 541 | public any function listEventTrackers( 542 | required string datasetGroupArn, 543 | numeric maxResults, 544 | string nextToken 545 | ) { 546 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 547 | var args = { 'datasetGroupArn': arguments.datasetGroupArn }; 548 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 549 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 550 | 551 | return apiCall( requestSettings, 'ListEventTrackers', args ); 552 | } 553 | 554 | /** 555 | * Returns a list of available recipes. The response provides the properties for each recipe, including the recipe's Amazon Resource Name (ARN). 556 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListRecipes.html 557 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 558 | * @nextToken Optional string. A token returned from the previous call to ListEventTrackers for getting the next set of event trackers (if they exist). 559 | * @recipeProvider Optional string. The default is SERVICE. 560 | */ 561 | public any function listRecipes( 562 | numeric maxResults, 563 | string nextToken, 564 | string recipeProvider 565 | ) { 566 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 567 | var args = { }; 568 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 569 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 570 | if ( !isNull( arguments.recipeProvider ) ) args[ 'recipeProvider' ] = arguments.recipeProvider; 571 | 572 | return apiCall( requestSettings, 'ListRecipes', args ); 573 | } 574 | 575 | /** 576 | * Returns the list of schemas associated with the account. The response provides the properties for each schema, including the Amazon Resource Name (ARN). 577 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListSchemas.html 578 | * @maxResults Optional numeric. The maximum number of schemas to return. between 1 and 100. 579 | * @nextToken Optional string. A token returned from the previous call to ListEventTrackers for getting the next set of event trackers (if they exist). 580 | */ 581 | public any function listSchemas( 582 | numeric maxResults, 583 | string nextToken 584 | ) { 585 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 586 | var args = { }; 587 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 588 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 589 | 590 | return apiCall( requestSettings, 'ListSchemas', args ); 591 | } 592 | 593 | /** 594 | * Returns a list of solutions that use the given dataset group. When a dataset group is not specified, all the solutions associated with the account are listed. The response provides the properties for each solution, including the Amazon Resource Name (ARN). For more information on solutions, see CreateSolution. 595 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListSolutions.html 596 | * @datasetGroupArn a string: The Amazon Resource Name (ARN) of the dataset group. 597 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 598 | * @nextToken Optional string. A token returned from the previous call to ListSolutions for getting the next set of solutions (if they exist). 599 | */ 600 | public any function listSolutions( 601 | required string datasetGroupArn, 602 | numeric maxResults, 603 | string nextToken 604 | ) { 605 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 606 | var args = { 'datasetGroupArn': arguments.datasetGroupArn }; 607 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 608 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 609 | 610 | return apiCall( requestSettings, 'ListSolutions', args ); 611 | } 612 | 613 | /** 614 | * Returns a list of solution versions for the given solution. When a solution is not specified, all the solution versions associated with the account are listed. The response provides the properties for each solution version, including the Amazon Resource Name (ARN). For more information on solutions, see CreateSolution. 615 | * https://docs.aws.amazon.com/personalize/latest/dg/API_ListSolutionVersions.html 616 | * @solutionArn a string: The Amazon Resource Name (ARN) of the solution. 617 | * @maxResults Optional numeric. The maximum number of solutions to return. between 1 and 100. 618 | * @nextToken Optional string. A token returned from the previous call to ListSolutions for getting the next set of solutions (if they exist). 619 | */ 620 | public any function listSolutionVersions( 621 | required string solutionArn, 622 | numeric maxResults, 623 | string nextToken 624 | ) { 625 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 626 | var args = { 'solutionArn': arguments.solutionArn }; 627 | if ( !isNull( arguments.maxResults ) ) args[ 'maxResults' ] = arguments.maxResults; 628 | if ( !isNull( arguments.nextToken ) ) args[ 'nextToken' ] = arguments.nextToken; 629 | 630 | return apiCall( requestSettings, 'ListSolutionVersions', args ); 631 | } 632 | 633 | /** 634 | * Updates a campaign by either deploying a new solution or changing the value of the campaign's minProvisionedTPS parameter. 635 | To update a campaign, the campaign status must be ACTIVE or CREATE FAILED. Check the campaign status using the DescribeCampaign API. 636 | * https://docs.aws.amazon.com/personalize/latest/dg/API_UpdateCampaign.html 637 | * @campaignArn a string: The Amazon Resource Name (ARN) of the campaign. 638 | * @minProvisionedTPS Optional numeric. Specifies the requested minimum provisioned transactions (recommendations) per second that Amazon Personalize will support. 639 | * @solutionVersionArn Optional string. The ARN of a new solution version to deploy. 640 | */ 641 | public any function updateCampaign( 642 | required string campaignArn, 643 | numeric minProvisionedTPS, 644 | string solutionVersionArn 645 | ) { 646 | var requestSettings = api.resolveRequestSettings( argumentCollection = arguments ); 647 | var args = { 'campaignArn': arguments.campaignArn }; 648 | if ( !isNull( arguments.minProvisionedTPS ) ) args[ 'minProvisionedTPS' ] = arguments.minProvisionedTPS; 649 | if ( !isNull( arguments.solutionVersionArn ) ) args[ 'solutionVersionArn' ] = arguments.solutionVersionArn; 650 | 651 | return apiCall( requestSettings, 'updateCampaign', args ); 652 | } 653 | 654 | private any function apiCall( 655 | required struct requestSettings, 656 | required string target, 657 | struct payload = { } 658 | ) { 659 | var host = variables.service & '.' & requestSettings.region & '.amazonaws.com'; 660 | 661 | var payloadString = serializeJSON( payload ); 662 | var headers = { }; 663 | headers[ 'X-Amz-Target' ] = 'AmazonPersonalize.#target#'; 664 | headers[ 'Content-Type' ] = 'application/x-amz-json-1.1'; 665 | 666 | var apiResponse = api.call( 667 | variables.service, 668 | host, 669 | requestSettings.region, 670 | 'POST', 671 | '/', 672 | { }, 673 | headers, 674 | payloadString, 675 | requestSettings.awsCredentials 676 | ); 677 | apiResponse[ 'data' ] = deserializeJSON( apiResponse.rawData ); 678 | 679 | return apiResponse; 680 | } 681 | 682 | } 683 | --------------------------------------------------------------------------------