3
2
2023-07-13
(C) Questetra, Inc. (MIT License)
This item adds or updates a contact on SendGrid. 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/
https://support.questetra.com/ja/bpmn-icons/service-task-sendgrid-contact-upsert/
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=
{
configs.put('conf_Auth', 'SendGrid');
setDataItem('Email', 1, 'STRING_TEXTFIELD', email);
setDataItem('ListIds', 2, 'STRING_TEXTAREA', listIds);
setDataItem('AlternateEmails', 3, 'STRING_TEXTAREA', alternateEmails);
setDataItem('LastName', 4, 'STRING_TEXTFIELD', lastName);
setDataItem('FirstName', 5, 'STRING_TEXTFIELD', firstName);
setDataItem('Country', 6, 'STRING_TEXTFIELD', country);
setDataItem('PostalCode', 7, 'STRING_TEXTFIELD', postalCode);
setDataItem('Region', 8, 'STRING_TEXTFIELD', region);
setDataItem('City', 9, 'STRING_TEXTFIELD', city);
setDataItem('Address1', 10, 'STRING_TEXTFIELD', address1);
setDataItem('Address2', 11, 'STRING_TEXTFIELD', address2);
};
/**
* データ項目を作成し、config にセットする
* @param name config 名の conf_ 以降
* @param index
* @param type
* @param value
*/
const setDataItem = (name, index, type, value) => {
const dataDef = engine.createDataDefinition(name, index, `q_${name}`, type);
engine.setData(dataDef, value);
configs.putObject(`conf_${name}`, dataDef);
};
/**
* 異常系のテスト
* @param func
* @param errorMsg
*/
const assertError = (func, errorMsg) => {
try {
func();
fail();
} catch (e) {
expect(e.toString()).toEqual(errorMsg);
}
};
/**
* 指定個数のデータを改行区切りにした文字列を生成する
* @param num
* @return string
*/
const createListString = (num) => {
let string = '';
for (let i = 0; i < num; i++) {
string += `item${i}\n`;
}
return string;
};
/**
* 指定の長さの文字列を作成
* @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, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
assertError(main, `Email Address is blank.`);
});
/**
* メールアドレスが長すぎる
*/
test('Email Address is too long', () => {
const email = createString(MAX_EMAIL_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
assertError(main, `Email Address must be within ${MAX_EMAIL_LENGTH} characters.`);
});
/**
* 代替メールアドレスの個数が多すぎる
*/
test('Alternate Emails are too many', () => {
const email = createString(MAX_EMAIL_LENGTH);
const alternateEmailsStr = createListString(MAX_ALTERNATE_EMAIL_NUM + 1);
prepareConfigs(email, 'list1\nlist2', alternateEmailsStr, null, null, null, null, null, null, null, null);
assertError(main, `The maximum number of alternate emails is ${MAX_ALTERNATE_EMAIL_NUM}.`);
});
/**
* 代替メールアドレスが長すぎる
*/
test('Alternate Email is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const alternateEmailsStr = createListString(MAX_ALTERNATE_EMAIL_NUM - 1)
+ createString(MAX_EMAIL_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', alternateEmailsStr, null, null, null, null, null, null, null, null);
assertError(main, `Each alternate email must be within ${MAX_EMAIL_LENGTH} characters.`);
});
/**
* 姓が長すぎる
*/
test('Last Name is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const lastName = createString(MAX_NAME_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, lastName, null, null, null, null, null, null, null);
assertError(main, `Last Name must be within ${MAX_NAME_LENGTH} characters.`);
});
/**
* 名が長すぎる
*/
test('First Name is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const firstName = createString(MAX_NAME_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, firstName, null, null, null, null, null, null);
assertError(main, `First Name must be within ${MAX_NAME_LENGTH} characters.`);
});
/**
* 国が長すぎる
*/
test('Country is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const country = createString(MAX_NAME_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, country, null, null, null, null, null);
assertError(main, `Country must be within ${MAX_NAME_LENGTH} characters.`);
});
/**
* 郵便番号が長すぎる
*/
test('Postal Code is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const postalCode = createString(MAX_POSTAL_CODE_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, postalCode, null, null, null, null);
assertError(main, `Postal Code must be within ${MAX_POSTAL_CODE_LENGTH} characters.`);
});
/**
* 都道府県が長すぎる
*/
test('Region is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const region = createString(MAX_NAME_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, region, null, null, null);
assertError(main, `Region must be within ${MAX_NAME_LENGTH} characters.`);
});
/**
* 市区町村が長すぎる
*/
test('City is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const city = createString(MAX_CITY_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, null, city, null, null);
assertError(main, `City must be within ${MAX_CITY_LENGTH} characters.`);
});
/**
* 住所 1 が長すぎる
*/
test('Address 1st Line is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const address1 = createString(MAX_FIELD_VALUE_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, null, null, address1, null);
assertError(main, `Address 1st Line must be within ${MAX_FIELD_VALUE_LENGTH} characters.`);
});
/**
* 住所 2 が長すぎる
*/
test('Address 2nd Line is too long', () => {
const email = createString(MAX_EMAIL_LENGTH);
const address2 = createString(MAX_FIELD_VALUE_LENGTH + 1);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, null, null, null, address2);
assertError(main, `Address 2nd Line must be within ${MAX_FIELD_VALUE_LENGTH} characters.`);
});
/**
* 宛先を追加/更新する API リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
* @param request.contentType
* @param request.body
* @param listIds
* @param contact
*/
const assertUpsertRequest = ({url, method, contentType, body}, listIds, 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.list_ids).toEqual(listIds);
expect(bodyObj.contacts[0]).toEqual(contact);
};
/**
* リクエストボディのアサート用の宛先オブジェクトを作成する
* 同じロジックだとテストにならないので、別のロジックで作成
* @param email
* @param alternateEmails
* @param lastName
* @param firstName
* @param country
* @param postalCode
* @param region
* @param city
* @param address1
* @param address2
* @return contact
*/
const createContact = (email, alternateEmails, lastName, firstName, country, postalCode, region,
city, address1, address2) => {
const contact = {email};
assignIfNotNull(contact, 'alternate_emails', alternateEmails);
assignIfNotNull(contact, 'last_name', lastName);
assignIfNotNull(contact, 'first_name', firstName);
assignIfNotNull(contact, 'country', country);
assignIfNotNull(contact, 'postal_code', postalCode);
assignIfNotNull(contact, 'state_province_region', region);
assignIfNotNull(contact, 'city', city);
assignIfNotNull(contact, 'address_line_1', address1);
assignIfNotNull(contact, 'address_line_2', address2);
return contact;
};
/**
* 値が null でない場合のみ、オブジェクトに追加する
* @param obj
* @param key
* @param value
*/
const assignIfNotNull = (obj, key, value) => {
if (value !== null) {
Object.assign(obj, {[key]: value});
}
};
/**
* 宛先を追加/更新する API リクエストでエラー
*/
test('Fail to upsert contact', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
const listIds = ['list1', 'list2'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
httpClient.setRequestHandler((request) => {
assertUpsertRequest(request, listIds, contact);
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 request.contentType
* @param request.body
* @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, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
const listIds = ['list1', 'list2'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, contact);
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, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
const listIds = ['list1', 'list2'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, contact);
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.');
});
/**
* 成功
* リスト ID を文字型データ項目で指定
* その他のフィールドはすべて空
*/
test('Succeed - List IDs set by STRING, the other fields are blank', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
const listIds = ['list1', 'list2'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, contact);
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);
});
/**
* 成功
* リスト ID を文字型データ項目で指定し、値が空
* その他のフィールドはすべて指定
*/
test('Succeed - List IDs set by STRING with its value null, the other fields set at max length', () => {
const email = createString(MAX_EMAIL_LENGTH);
const alternateEmailsStr = createListString(MAX_ALTERNATE_EMAIL_NUM);
const lastName = createString(MAX_NAME_LENGTH);
const firstName = createString(MAX_NAME_LENGTH);
const country = createString(MAX_NAME_LENGTH);
const postalCode = createString(MAX_POSTAL_CODE_LENGTH);
const region = createString(MAX_NAME_LENGTH);
const city = createString(MAX_CITY_LENGTH);
const address1 = createString(MAX_FIELD_VALUE_LENGTH);
const address2 = createString(MAX_FIELD_VALUE_LENGTH);
prepareConfigs(email, null, alternateEmailsStr, lastName, firstName, country, postalCode, region, city, address1, address2);
const listIds = [];
const alternateEmails = alternateEmailsStr.split('\n').filter(email => email !== '');
expect(alternateEmails.length).toEqual(MAX_ALTERNATE_EMAIL_NUM);
const contact = createContact(email, alternateEmails, lastName, firstName, country, postalCode, region, city, address1, address2);
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, 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 - Only Email is set', () => {
const email = 'test@example.com';
const dummy = 'dummy';
prepareConfigs(email, dummy, dummy, dummy, dummy, dummy, dummy, dummy, dummy, dummy, dummy);
configs.put('conf_ListIds', '');
configs.put('conf_AlternateEmails', '');
configs.put('conf_LastName', '');
configs.put('conf_FirstName', '');
configs.put('conf_Country', '');
configs.put('conf_PostalCode', '');
configs.put('conf_Region', '');
configs.put('conf_City', '');
configs.put('conf_Address1', '');
configs.put('conf_Address2', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, undefined, {email}); // メールアドレスのみ
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);
});
/**
* 成功
* リスト ID を選択型データ項目で指定
* その他のフィールドはすべて空
*/
test('Succeed - List IDs set by SELECT, the other fields are blank', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, 'dummy', null, null, null, null, null, null, null, null, null);
const listIdsSelect = new java.util.ArrayList();
for (let i = 0; i < 5; i++) {
const item = engine.createItem(`list${i+1}`, `リスト ${i+1}`);
listIdsSelect.add(item);
}
setDataItem('ListIds', 12, 'SELECT_CHECKBOX', listIdsSelect);
const listIds = ['list1', 'list2', 'list3', 'list4', 'list5'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, 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);
});
/**
* 成功
* リスト ID を選択型データ項目で指定し、何も選択されていない
* その他のフィールドはすべて空
*/
test('Succeed - List IDs set by SELECT with none selected, the other fields are blank', () => {
const email = createString(MAX_EMAIL_LENGTH);
prepareConfigs(email, 'dummy', null, null, null, null, null, null, null, null, null);
const listIdsSelect = new java.util.ArrayList();
setDataItem('ListIds', 12, 'SELECT_CHECKBOX', listIdsSelect);
const listIds = [];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, contact);
reqCount++;
return httpClient.createHttpResponse(202, 'application/json', '{"job_id": "job5"}');
}
assertCheckStatusRequest(request, 'job5');
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, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
const listIds = ['list1', 'list2'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, contact);
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": "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, 'list1\nlist2', null, null, null, null, null, null, null, null, null);
const listIds = ['list1', 'list2'];
const contact = createContact(email, [], '', '', '', '', '', '', '', '');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertUpsertRequest(request, listIds, contact);
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);
});
]]>