3
2
2023-07-03
(C) Questetra, Inc. (MIT License)
This item adds or updates a contact on SendGrid with the specified custom field values. If a contact with the specified email address already exists, the contact will be updated.
この工程は、SendGrid の宛先を追加または更新し、指定したカスタムフィールドに値を設定します。指定したメールアドレスの宛先がすでにある場合、その宛先が更新されます。
https://support.questetra.com/bpmn-icons/service-task-sendgrid-contact-upsert-custom-fields/
https://support.questetra.com/ja/bpmn-icons/service-task-sendgrid-contact-upsert-custom-fields/
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADBUlEQVRYR8WXS08TURTH/5cWBeXZ
ipHFjBh3JIYSdKELYePGZCYS4jMxtiauwU+gJm40JpYPYKhxodEoj+4R4lYrjQsXimKrUhKRNxNC
22vuTMcZ5s50psLgbCY5c++c3zn33PMg+M8PqUh/MnMOFN0gJAKgCQB7s2cKwCIoZe8JyOKo1/+6
AwwvNCG42g9KB0AIU+r+ULoIQuLI1w2it3mx3IbyAGPfo0DxoWfFVk0qCGKQxBEnCGeAZDYOoN/d
XA8rKI1DFm/arbQHSGYSALnm4dfel1CagCzGrBt4ABfL+w7V4lhDNae4LkiwmqecPKsU8Ci7pssH
IQkD5kVbAdiZEzpUzqzJUy04HdrLLfm4mse9z8uc/OzBWlxMzZvktNccEwYAi/bAyle3gHMCSC1t
ouvNHAfwpDOEq+9/G3IWmIX6I/rtMACS2dsAbrkd6rYBNAV3IAlMHwyAsQy7u427AsC8IIvNBgDL
cCDDbsrZ9x3yAAAtFjQP2ET+DXE/zrTUcEztddVorani5OO/NvBNySNICIIECBCCKgJMr+Vxf3rF
zjb1RmgAY9kJEHSbVz3vCuN8ay238ct6AUfHZzn565Mt6Anzt2Mkp6D3rfkWlLZSTEIWenQPzAA4
7AfAq5yCPjsAVsAkoVMH4DLITnngxayCC+9sPMCslQTiO8Czn+u4nDLlAbObTQC+HcHTH+u4Yk5E
BkAakhBxDMKXx8OINOzhgq1IKeY2ipz8UmoeoycOcPLhnIK7n/gUDUsQcqV3qCOEWJp3XaV5oExu
MV1Dm0TkP4A5Eam5YGsq9hWA0iXIotreORYjXwFsi5FWjmf0guQbALO+UN/Gl2P1GIyG5EF7I8LV
AS6G2vYFwLof6/NheRPX0wse6plTQ6Jv3clmlMf52wfon3avKQV9DEmMWpl2py03BZ13ALVPUEex
hJdOyfbwWcARRP9tMNH/qI1mA6XRzLVlU7epitXRLL690cxqlpYxe0ARAVGH047SkjQo2Bg2BdCJ
chZXdgQeLtV2l/wBk2V1MIOcaTsAAAAASUVORK5CYII=
} fieldConfigMap
*/
const prepareConfigs = (email, fieldConfigMap) => {
configs.put('conf_Auth', 'SendGrid');
setDataItem('Email', 10, 'STRING_TEXTFIELD', email);
fieldConfigMap.forEach((fieldConfig, i) => {
configs.put(`conf_FieldName${i}`, fieldConfig.name);
setDataItem(`FieldValue${i}`, i, fieldConfig.type, fieldConfig.value);
});
};
/**
* データ項目を作成し、config にセットする
* @param name config 名の conf_ 以降
* @param index
* @param type
* @param value
*/
const setDataItem = (name, index, type, value) => {
if (type === null) {
return;
}
const dataDef = engine.createDataDefinition(name, index, `q_${name}`, type);
configs.putObject(`conf_${name}`, dataDef);
if (value === null) {
return;
}
switch (type) {
case 'STRING_TEXTFIELD':
engine.setData(dataDef, value);
break;
case 'DECIMAL':
engine.setData(dataDef, java.math.BigDecimal.valueOf(value));
break;
case 'DATE_YMD':
engine.setData(dataDef, java.sql.Date.valueOf(value));
break;
}
};
/**
* 異常系のテスト
* @param func
* @param errorMsg
*/
const assertError = (func, errorMsg) => {
try {
func();
fail();
} catch (e) {
expect(e.toString()).toEqual(errorMsg);
}
};
/**
* 指定の長さの文字列を作成
* @param length
* @return string
*/
const createString = (length) => {
const sourceStr = 'abcdefghijklmnopqrstuvwxyz';
const string = sourceStr.repeat(Math.floor(length / sourceStr.length))
+ sourceStr.slice(0, length % sourceStr.length);
return string;
}
/**
* メールアドレスが空
*/
test('Email Address is blank', () => {
prepareConfigs(null, new Map());
assertError(main, `Email Address is blank.`);
});
/**
* メールアドレスが長すぎる
*/
test('Email Address is too long', () => {
const email = createString(MAX_EMAIL_LENGTH + 1);
prepareConfigs(email, new Map());
assertError(main, `Email Address must be within ${MAX_EMAIL_LENGTH} characters.`);
});
/**
* 宛先を追加/更新する API リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
* @param request.contentType
* @param request.body
* @param contact
*/
const assertUpsertRequest = ({url, method, contentType, body}, contact) => {
expect(url).toEqual('https://api.sendgrid.com/v3/marketing/contacts');
expect(method).toEqual('PUT');
expect(contentType).toEqual('application/json');
const bodyObj = JSON.parse(body);
expect(bodyObj.contacts[0]).toEqual(contact);
};
/**
* 宛先を追加/更新する API リクエストでエラー
*/
test('Fail to upsert contact', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, new Map()); // カスタムフィールドの指定なし
httpClient.setRequestHandler((request) => {
assertUpsertRequest(request, {email});
return httpClient.createHttpResponse(400, 'application/json', '{}');
});
assertError(main, 'Failed to upsert contact. status: 400');
});
/**
* ジョブの処理状況を確認する API リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
* @param jobId
*/
const assertCheckStatusRequest = ({url, method}, jobId) => {
expect(url).toEqual(`https://api.sendgrid.com/v3/marketing/contacts/imports/${jobId}`);
expect(method).toEqual('GET');
};
/**
* ジョブの処理状況を確認する API リクエストでエラー
*/
test('Fail to get upsert status', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, new Map()); // カスタムフィールドの指定なし
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, {email});
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job1"}');
}
assertCheckStatusRequest(request, 'job1');
return httpClient.createHttpResponse(400, 'application/json', '{}');
});
assertError(main, 'Failed to get upsert status. status: 400');
});
/**
* 1 回目のステータス確認で、ジョブが異常終了
*/
test('Fail to complete upserting in main()', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, new Map()); // カスタムフィールドの指定なし
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, {email});
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job1"}');
}
assertCheckStatusRequest(request, 'job1');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "failed"}');
});
assertError(main, 'Failed to complete upserting the contact.');
});
/**
* 成功
* カスタムフィールドを指定しない場合
*/
test('Succeed - No Custom Fields', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, new Map()); // カスタムフィールドの指定なし
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, {email});
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job1"}');
}
assertCheckStatusRequest(request, 'job1');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "completed"}');
});
expect(main()).toEqual(undefined);
});
/**
* フィールド名が空なのに、値のデータ項目が選択されている
*/
test('Field Name is blank while its value is selected', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(3, {name: '', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
assertError(main, `Custom Field Name 3 is blank while its value is selected.`);
});
/**
* フィールド名の指定が重複
*/
test('Same Field Name is set multiple times', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(1, {name: 'field_1', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
fieldConfigMap.set(3, {name: 'field_1', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
assertError(main, `Custom Field Name "field_1" is set multiple times.`);
});
/**
* フィールド名は設定されているのに、値のデータ項目が選択されていない
*/
test('Field Value is not selected while its field name is set', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(4, {name: 'field_4', type: null, value: null});
prepareConfigs(email, fieldConfigMap);
assertError(main, `Value 4 is not selected while its field name is set.`);
});
/**
* フィールドの値が文字列で、長すぎる
*/
test('Field Value is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
const fieldValue = createString(MAX_FIELD_VALUE_LENGTH + 1);
fieldConfigMap.set(1, {name: 'field_1', type: 'STRING_TEXTFIELD', value: fieldValue});
prepareConfigs(email, fieldConfigMap);
assertError(main, `Custom Field Value of "field_1" must be within ${MAX_FIELD_VALUE_LENGTH} characters.`);
});
/**
* 全カスタムフィールドの一覧を取得する API リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
*/
const assertGetAllCustomFieldsRequest = ({url, method}) => {
expect(url).toEqual('https://api.sendgrid.com/v3/marketing/field_definitions');
expect(method).toEqual('GET');
};
/**
* 全カスタムフィールドの一覧を取得する API リクエストでエラー
*/
test('Fail to get all custom fields', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(1, {name: 'field_1', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
httpClient.setRequestHandler((request) => {
assertGetAllCustomFieldsRequest(request);
return httpClient.createHttpResponse(400, 'application/json', '{}');
});
assertError(main, 'Failed to get field definitions. status: 400');
});
const ALL_CUSTOM_FIELDS_RESPONSE = {
custom_fields: [
{
id: '1T',
name: 'field_1',
field_type: 'Text'
},
{
id: '2T',
name: 'field_2',
field_type: 'Text'
},
{
id: '3T',
name: 'field_3',
field_type: 'Text'
},
{
id: '4T',
name: 'field_4',
field_type: 'Text'
},
{
id: '5T',
name: 'field_5',
field_type: 'Text'
},
{
id: '6T',
name: 'field_6',
field_type: 'Text'
},
{
id: '7T',
name: 'field_7',
field_type: 'Text'
},
{
id: '8T',
name: 'field_8',
field_type: 'Text'
},
{
id: '9N',
name: 'field_9',
field_type: 'Number'
},
{
id: '10D',
name: 'field_10',
field_type: 'Date'
}
]
};
/**
* 存在しないカスタムフィールド名を指定
*/
test('Custom Field does not exist', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(1, {name: 'field_100', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
httpClient.setRequestHandler((request) => {
assertGetAllCustomFieldsRequest(request);
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
});
assertError(main, 'Custom Field named "field_100" does not exist.');
});
/**
* 文字型のカスタムフィールドの値を、文字型以外で指定
*/
test('Custom Field is Text type but its value is not set by STRING_TEXTFIELD type data item', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(1, {name: 'field_1', type: 'DECIMAL', value: 123});
prepareConfigs(email, fieldConfigMap);
httpClient.setRequestHandler((request) => {
assertGetAllCustomFieldsRequest(request);
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
});
assertError(main, 'Custom Field "field_1" is Text type. Its value must be set by STRING_TEXTFIELD type data item.');
});
/**
* 数値型のカスタムフィールドの値を、数値型以外で指定
*/
test('Custom Field is Number type but its value is not set by DECIMAL type data item', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(2, {name: 'field_9', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
httpClient.setRequestHandler((request) => {
assertGetAllCustomFieldsRequest(request);
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
});
assertError(main, 'Custom Field "field_9" is Number type. Its value must be set by DECIMAL type data item.');
});
/**
* 日付型のカスタムフィールドの値を、日付型以外で指定
*/
test('Custom Field is Date type but its value is not set by DATE_YMD type data item', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(3, {name: 'field_10', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
httpClient.setRequestHandler((request) => {
assertGetAllCustomFieldsRequest(request);
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
});
assertError(main, 'Custom Field "field_10" is Date type. Its value must be set by DATE_YMD type data item.');
});
/**
* 成功
* カスタムフィールドを最大個数、最長文字数の文字列で指定
*/
test('Succeed - Maximum number of Custom Fields', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
const customFields = {}; // リクエストボディのアサート用オブジェクト
const fieldValuePrefix = createString(MAX_FIELD_VALUE_LENGTH - 2);
for (let i = 0; i < FIELD_NUM; i++) {
const fieldName = `field_${i + 1}`;
const fieldId = `${i + 1}T`;
const fieldValue = `${fieldValuePrefix}_${i + 1}`;
fieldConfigMap.set(i + 1, {name: fieldName, type: 'STRING_TEXTFIELD', value: fieldValue});
Object.assign(customFields, {[fieldId]: fieldValue});
}
prepareConfigs(email, fieldConfigMap);
const contact = {
email,
custom_fields: customFields
};
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetAllCustomFieldsRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
}
if (reqCount === 1) {
assertUpsertRequest(request, contact);
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job2"}');
}
assertCheckStatusRequest(request, 'job2');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "completed"}');
});
expect(main()).toEqual(undefined);
});
/**
* 成功
* 文字型、数値型、日付型のカスタムフィールドが混在
*/
test('Succeed - All types of Custom Fields', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(1, {name: 'field_1', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
fieldConfigMap.set(4, {name: 'field_9', type: 'DECIMAL', value: 123});
fieldConfigMap.set(7, {name: 'field_10', type: 'DATE_YMD', value: '2021-01-31'});
prepareConfigs(email, fieldConfigMap);
const customFields = {
'1T': 'フィールドの値',
'9N': 123,
'10D': '01/31/2021'
};
const contact = {
email,
custom_fields: customFields
};
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetAllCustomFieldsRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
}
if (reqCount === 1) {
assertUpsertRequest(request, contact);
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job3"}');
}
assertCheckStatusRequest(request, 'job3');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "completed"}');
});
expect(main()).toEqual(undefined);
});
/**
* 成功
* フィールドの値が null の場合、空文字列が送られる
*/
test('Succeed - Custom Data Value is null', () => {
const email = createString(MAX_EMAIL_LENGTH);
const fieldConfigMap = new Map();
fieldConfigMap.set(1, {name: 'field_1', type: 'STRING_TEXTFIELD', value: null});
fieldConfigMap.set(4, {name: 'field_9', type: 'DECIMAL', value: null});
fieldConfigMap.set(7, {name: 'field_10', type: 'DATE_YMD', value: null});
fieldConfigMap.set(8, {name: 'field_2', type: 'STRING_TEXTFIELD', value: 'フィールドの値'});
prepareConfigs(email, fieldConfigMap);
const customFields = {
'1T': '',
'9N': '',
'10D': '',
'2T': 'フィールドの値'
};
const contact = {
email,
custom_fields: customFields
};
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetAllCustomFieldsRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(ALL_CUSTOM_FIELDS_RESPONSE));
}
if (reqCount === 1) {
assertUpsertRequest(request, contact);
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job4"}');
}
assertCheckStatusRequest(request, 'job4');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "completed"}');
});
expect(main()).toEqual(undefined);
});
/**
* 2 回目のステータス確認で、ジョブが異常終了
*/
test('Fail to complete upserting in proceed()', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, new Map()); // カスタムフィールドの指定なし
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, {email});
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job5"}');
}
assertCheckStatusRequest(request, 'job5');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "pending"}');
});
expect(main()).toEqual(false);
expect(engine.restoreTemporaryData()).toEqual('job5');
httpClient.setRequestHandler((request) => {
assertCheckStatusRequest(request, 'job5');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "errored"}');
});
assertError(proceed, 'Failed to complete upserting the contact.');
});
/**
* 成功
* proceed() のテスト
* 3 回目のステータス確認で、ジョブが完了
*/
test('Succeed - Complete in 3rd request', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, new Map()); // カスタムフィールドの指定なし
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, {email});
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job6"}');
}
assertCheckStatusRequest(request, 'job6');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "pending"}');
});
expect(main()).toEqual(false);
expect(engine.restoreTemporaryData()).toEqual('job6');
httpClient.setRequestHandler((request) => {
assertCheckStatusRequest(request, 'job6');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "pending"}');
});
expect(proceed()).toEqual(false);
httpClient.setRequestHandler((request) => {
assertCheckStatusRequest(request, 'job6');
return httpClient.createHttpResponse(200, 'application/json', '{"status": "completed"}');
});
expect(proceed()).toEqual(undefined);
});
]]>