UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

476 lines (475 loc) 22.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.call = call; const GMO = require("@motionpicture/gmo-service"); const createDebug = require("debug"); const factory = require("../../factory"); const person2username_1 = require("../payment/any/person2username"); const account_1 = require("../../repo/account"); const action_1 = require("../../repo/action"); const ownershipInfo_1 = require("../../repo/ownershipInfo"); const creditCard_1 = require("../../repo/paymentMethod/creditCard"); const paymentService_1 = require("../../repo/paymentService"); const person_1 = require("../../repo/person"); const setting_1 = require("../../repo/setting"); const task_1 = require("../../repo/task"); const debug = createDebug('chevre-domain:service:task:deletePerson'); // type IOwnershipInfoPermit = factory.ownershipInfo.IPermitAsGood; const ADMIN_PROVIDER_NAME = 'Google'; let cognitoIdentityServiceProvider; /** * タスク実行関数 */ function call(params) { return (_a) => __awaiter(this, [_a], void 0, function* ({ connection, settings }) { if (cognitoIdentityServiceProvider === undefined) { const { CognitoIdentityProvider } = yield Promise.resolve().then(() => require('@aws-sdk/client-cognito-identity-provider')); const { fromEnv } = yield Promise.resolve().then(() => require('@aws-sdk/credential-providers')); cognitoIdentityServiceProvider = new CognitoIdentityProvider({ apiVersion: 'latest', region: 'ap-northeast-1', credentials: fromEnv() }); } const settingRepo = new setting_1.SettingRepo(connection); const setting = yield settingRepo.findOne({ project: { id: { $eq: '*' } } }, ['userPoolIdOld']); if (typeof (setting === null || setting === void 0 ? void 0 : setting.userPoolIdOld) !== 'string') { throw new factory.errors.NotFound('setting.userPoolIdOld'); } const newPersonRepo = new person_1.PersonRepo({ userPoolId: params.data.userPoolId, cognitoIdentityServiceProvider }); const oldPersonRepo = new person_1.PersonRepo({ // userPoolId: settings.userPoolIdOld, userPoolId: setting.userPoolIdOld, cognitoIdentityServiceProvider }); const paymentServiceRepo = new paymentService_1.PaymentServiceRepo(connection); let creditCardRepo; if (typeof params.data.paymentMethodType4creditCard === 'string' && params.data.paymentMethodType4creditCard.length > 0) { const credentials = yield getCreditCardPaymentServiceChannel({ project: { id: params.project.id }, paymentMethodType: params.data.paymentMethodType4creditCard })({ paymentService: paymentServiceRepo }); creditCardRepo = new creditCard_1.CreditCardRepo({ siteId: credentials.siteId, sitePass: credentials.sitePass, cardService: new GMO.service.Card({ endpoint: credentials.endpoint, useFetch: settings.gmo.useFetch }, { timeout: (params.data.executeBackground) ? settings.gmo.timeout // tslint:disable-next-line:no-magic-numbers : 20000 // cronで実行の場合は長めに(2024-10-05~) }) }); } yield deleteById(Object.assign(Object.assign({}, params.data), { project: { id: params.project.id } }), setting)({ account: new account_1.AccountRepo(connection), action: new action_1.ActionRepo(connection), creditCard: creditCardRepo, ownershipInfo: new ownershipInfo_1.OwnershipInfoRepo(connection), paymentService: paymentServiceRepo, newPerson: newPersonRepo, oldPerson: oldPersonRepo, task: new task_1.TaskRepo(connection), cognitoIdentityServiceProvider }); }); } /** * 会員削除処理 */ function deleteById(params, setting) { // tslint:disable-next-line:max-func-body-length return (repos) => __awaiter(this, void 0, void 0, function* () { var _a; const deleteMemberAction = { agent: params.agent, object: { id: params.id, typeOf: factory.personType.Person, migrate: params.migrate, physically: params.physically // discontinue(2025-03-29~) // ...(typeof params.migratePersonRecipientUrl === 'string') // ? { migratePersonRecipientUrl: params.migratePersonRecipientUrl } : undefined }, project: { id: params.project.id, typeOf: factory.organizationType.Project }, typeOf: factory.actionType.DeleteAction }; const action = yield repos.action.start(deleteMemberAction); let existingPeople; try { // const project = <Pick<factory.project.IProject, 'settings' | 'id'>>await repos.project.findById({ // id: params.project.id, // inclusion: ['settings'] // }); existingPeople = yield repos.newPerson.search({ id: params.id }); // exclude ADMIN_PROVIDER_NAME const username = (_a = existingPeople.at(0)) === null || _a === void 0 ? void 0 : _a.Username; const isAdminPerson = typeof username === 'string' && username.startsWith(ADMIN_PROVIDER_NAME, 0); if (isAdminPerson) { throw new factory.errors.Argument('id', `${ADMIN_PROVIDER_NAME} people cannot be deleted`); } // discontinue(2025-03-29~) // 移行の場合、全所有権情報通知タスクを作成 // if (params.migrate && typeof params.migratePersonRecipientUrl === 'string') { // await createInformTask({ // id: params.id, // project: { id: params.project.id }, // now: action.startDate, // migratePersonRecipientUrl: params.migratePersonRecipientUrl // })(repos); // } if (!params.migrate) { // 移行でなければDeleteTransactionタスクを作成(2023-07-03~) yield createDeleteTransactionTask({ id: params.id, project: { id: params.project.id }, now: action.startDate })({ task: repos.task }); } if (existingPeople.length > 0) { if (repos.creditCard !== undefined) { // クレジットカード削除 yield deleteCreditCardsById({ id: params.id, useUsernameAsGMOMemberId: params.useUsernameAsGMOMemberId }, setting)({ person: repos.newPerson, creditCard: repos.creditCard, cognitoIdentityServiceProvider: repos.cognitoIdentityServiceProvider }); } } // 所有権削除 debug('task:deletePerson:deleteById: deleteOwnershipInfosById processing... personId:', params.id); yield deleteOwnershipInfosById({ id: params.id, project: { id: params.project.id } })({ ownershipInfo: repos.ownershipInfo }); if (existingPeople.length > 0) { // 会員削除 if (params.physically === true) { debug('task:deletePerson:deleteById: deleteById processing...userId:', params.id); yield repos.newPerson.deleteById({ userId: params.id }); } else { // Cognitoユーザを無効にする yield repos.newPerson.globalSignOutAndDisable({ userId: params.id }); } } } catch (error) { try { yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error }); } catch (__) { // no op } throw error; } const actionResult = { existingPeople }; yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: actionResult }); }); } function getCreditCardPaymentServiceChannel(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { var _a, _b; const paymentServices = yield repos.paymentService.projectFields({ limit: 1, project: { id: { $eq: params.project.id } }, typeOf: { $eq: factory.service.paymentService.PaymentServiceType.CreditCard }, serviceType: { codeValue: { $eq: params.paymentMethodType } } }, ['availableChannel']); const paymentService = paymentServices.shift(); if (paymentService === undefined) { throw new factory.errors.NotFound('PaymentService'); } if (typeof paymentService.id !== 'string') { throw new factory.errors.NotFound('paymentService.id.id'); } const availableChannel = yield repos.paymentService.findAvailableChannelCreditCard({ project: { id: params.project.id }, id: paymentService.id }); // const availableChannel = paymentService?.availableChannel; if (typeof (availableChannel === null || availableChannel === void 0 ? void 0 : availableChannel.serviceUrl) !== 'string') { throw new factory.errors.NotFound('paymentService.availableChannel.serviceUrl'); } if (typeof ((_a = availableChannel === null || availableChannel === void 0 ? void 0 : availableChannel.credentials) === null || _a === void 0 ? void 0 : _a.siteId) !== 'string') { throw new factory.errors.NotFound('paymentService.availableChannel.credentials.siteId'); } if (typeof ((_b = availableChannel === null || availableChannel === void 0 ? void 0 : availableChannel.credentials) === null || _b === void 0 ? void 0 : _b.sitePass) !== 'string') { throw new factory.errors.NotFound('paymentService.availableChannel.credentials.sitePass'); } return { endpoint: availableChannel.serviceUrl, siteId: availableChannel.credentials.siteId, sitePass: availableChannel.credentials.sitePass }; }); } // function createInformTask(params: { // id: string; // project: { id: string }; // now: Date; // migratePersonRecipientUrl: string; // }) { // // tslint:disable-next-line:max-func-body-length // return async (repos: { // account: AccountRepo; // ownershipInfo: OwnershipInfoRepo; // newPerson: PersonRepo; // oldPerson: PersonRepo; // task: TaskRepo; // }) => { // const person = await repos.newPerson.findById({ userId: params.id }); // let oldUser: factory.person.IPerson | undefined; // const userIdentitiesStr = person.additionalProperty?.find((p) => p.name === 'identities')?.value; // if (typeof userIdentitiesStr === 'string' && userIdentitiesStr.length > 0) { // try { // const identities = JSON.parse(userIdentitiesStr); // if (Array.isArray(identities) && identities.length > 0) { // const userIdByIdentities = identities[0].userId; // if (typeof userIdByIdentities === 'string' && userIdByIdentities.length > 0) { // // oldUserは必ず存在するはず // oldUser = await repos.oldPerson.findById({ userId: userIdByIdentities }); // } // } // } catch (error) { // // tslint:disable-next-line:no-console // console.error('find oldUser throwed', error); // throw error; // } // } // const reservations = await repos.ownershipInfo.projectFields({ // project: { id: { $eq: params.project.id } }, // ownedBy: { id: params.id }, // typeOfGood: { issuedThrough: { typeOf: { $eq: factory.product.ProductType.EventService } } } // }); // const memberships = <factory.ownershipInfo.IOwnershipInfo<factory.ownershipInfo.IPermitAsGood>[]> // await repos.ownershipInfo.projectFields({ // limit: 1, // page: 1, // project: { id: { $eq: params.project.id } }, // ownedBy: { id: params.id }, // typeOfGood: { issuedThrough: { typeOf: { $eq: factory.product.ProductType.MembershipService } } }, // ownedFrom: params.now, // ownedThrough: params.now // }); // let paymentCards = <factory.ownershipInfo.IOwnershipInfo<factory.ownershipInfo.IPermitAsGood & { // balance: number; // }>[]> // await repos.ownershipInfo.projectFields({ // // 最も古い所有ペイメントカードをデフォルトペイメントカードとして扱う使用なので、ソート条件は以下の通り // sort: { ownedFrom: factory.sortType.Ascending }, // limit: 1, // page: 1, // project: { id: { $eq: params.project.id } }, // ownedBy: { id: params.id }, // typeOfGood: { issuedThrough: { typeOf: { $eq: factory.product.ProductType.PaymentCard } } }, // ownedFrom: params.now, // ownedThrough: params.now // }); // paymentCards = await Promise.all(paymentCards.map(async (paymentCard) => { // // 口座検索 // const accountNumber = String((<IOwnershipInfoPermit>paymentCard.typeOfGood).identifier); // const account = await repos.account.findByAccountNumber({ accountNumber }); // return { // ...paymentCard, // typeOfGood: { // ...paymentCard.typeOfGood, // balance: account.balance // } // }; // })); // // create task // let informTask: factory.task.IAttributes<factory.taskName.TriggerWebhook> & { // data: factory.task.triggerWebhook.IInformAnyResourceAction & { // object: factory.notification.person.IPersonAsNotification; // }; // }; // const informObject: factory.notification.person.IPersonAsNotification = { // id: person.id, // memberOf: person.memberOf, // typeOf: person.typeOf, // cognitoUser: { // Attributes: (<any>oldUser)?.Attributes, // Enabled: (<any>oldUser)?.Enabled, // UserCreateDate: (<any>oldUser)?.UserCreateDate, // UserLastModifiedDate: (<any>oldUser)?.UserLastModifiedDate, // UserStatus: (<any>oldUser)?.UserStatus, // Username: (<any>oldUser)?.Username // }, // reservations: reservations.map((ownershipInfo) => { // const { id, typeOf, typeOfGood, ownedFrom, ownedThrough } = ownershipInfo; // return { id, typeOf, typeOfGood, ownedFrom, ownedThrough }; // }), // memberships: memberships.map((ownershipInfo) => { // const { id, typeOf, typeOfGood, ownedFrom, ownedThrough } = ownershipInfo; // const { identifier } = typeOfGood; // return { // id, // typeOf, // typeOfGood: { identifier }, // ownedFrom, // ownedThrough // }; // }), // paymentCards: paymentCards.map((ownershipInfo) => { // const { id, typeOf, typeOfGood } = ownershipInfo; // const { balance, identifier } = typeOfGood; // return { // id, // typeOf, // typeOfGood: { balance, identifier } // }; // }) // }; // const informActionAttributes: factory.task.triggerWebhook.IInformAnyResourceAction & { // object: factory.notification.person.IPersonAsNotification; // } = { // optimize(2024-07-01~) // object: informObject, // recipient: { // // url: params.migratePersonRecipientUrl, // discontinue(2025-02-13~) // id: '', // name: 'NewUserPool', // typeOf: factory.creativeWorkType.WebApplication // }, // target: { // httpMethod: 'POST', // encodingType: factory.encodingFormat.Application.json, // typeOf: 'EntryPoint', // urlTemplate: params.migratePersonRecipientUrl // } // }; // informTask = { // project: { id: params.project.id, typeOf: factory.organizationType.Project }, // name: factory.taskName.TriggerWebhook, // status: factory.taskStatus.Ready, // runsAt: params.now, // remainingNumberOfTries: 10, // numberOfTried: 0, // executionResults: [], // data: informActionAttributes // }; // await repos.task.createInformTaskIfNotExist(informTask, { emitImmediately: true }); // }; // } function createDeleteTransactionTask(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { const deleteTransactionTasks = [ factory.transactionType.MoneyTransfer, factory.transactionType.PlaceOrder, factory.transactionType.ReturnOrder ].map((transactionType) => { return { project: { id: params.project.id, typeOf: factory.organizationType.Project }, name: factory.taskName.DeleteTransaction, status: factory.taskStatus.Ready, runsAt: params.now, remainingNumberOfTries: 3, numberOfTried: 0, executionResults: [], data: { object: { specifyingMethod: factory.task.deleteTransaction.SpecifyingMethod.AgentId, agent: { id: params.id }, project: { id: params.project.id }, typeOf: transactionType } } }; }); yield repos.task.saveMany(deleteTransactionTasks, { emitImmediately: true }); }); } function deleteOwnershipInfosById(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { // まず所有権削除 yield repos.ownershipInfo.deleteByOwnedById({ project: { id: params.project.id }, ownedBy: { id: params.id } }); }); } function sleep(waitTime) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve) => { setTimeout(() => { resolve(); }, waitTime); }); }); } const DELETE_CREDIT_CARD_MAX_RETRY_COUNT = 2; const DELETE_CREDIT_CARD_RETRY_INTERVAL_IN_MS = 1000; function deleteCreditCardsById(params, setting) { return (repos) => __awaiter(this, void 0, void 0, function* () { let retry = true; let numberOfTry = 0; while (numberOfTry >= 0) { try { numberOfTry += 1; if (numberOfTry > DELETE_CREDIT_CARD_MAX_RETRY_COUNT) { retry = false; } // retryInterval if (numberOfTry > 1) { yield sleep(DELETE_CREDIT_CARD_RETRY_INTERVAL_IN_MS * (numberOfTry - 1)); } // クレジットカード削除 if (params.useUsernameAsGMOMemberId) { const person = yield repos.person.findById({ userId: params.id }); let oldUsername; try { oldUsername = yield (0, person2username_1.person2username)(person, repos.cognitoIdentityServiceProvider, // settings setting); } catch (error) { let throwsPerson2usernameError = true; // oldUserが存在しないケースをハンドル if (error instanceof factory.errors.NotFound && error.entityName === 'User') { debug('task:deletePerson:deleteById: deleteCreditCardsById oldUsername not found', 'personId:', params.id, 'numberOfTry:', numberOfTry); throwsPerson2usernameError = false; } if (throwsPerson2usernameError) { throw error; } } if (typeof oldUsername === 'string') { debug('task:deletePerson:deleteById: deleteCreditCardsById processing... oldUsername:', oldUsername, 'personId:', params.id, 'numberOfTry:', numberOfTry); yield repos.creditCard.deleteAll({ personId: oldUsername }); } } else { yield repos.creditCard.deleteAll({ personId: params.id }); } debug('task:deletePerson:deleteById: deleteCreditCardsById processed. personId:', params.id, 'numberOfTry:', numberOfTry); break; } catch (error) { if (retry) { continue; } else { throw error; } } } }); }