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); }); ]]>