UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

210 lines (209 loc) 11.2 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.validateStartRequest = validateStartRequest; const jwt = require("jsonwebtoken"); const moment = require("moment"); const factory = require("../../../factory"); const ROLE_DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ'; function verifyOfferedByToken(params) { return __awaiter(this, void 0, void 0, function* () { let result; const { issuer, secret, token } = params; try { result = yield new Promise((resolve, reject) => { jwt.verify(token, secret, { issuer // ...(Array.isArray(params.audience)) ? { audience: params.audience } : undefined }, (err, decoded) => { if (err instanceof Error) { reject(err); } else { resolve(decoded); } }); }); } catch (error) { // JWTエラーをハンドリング if (error instanceof jwt.TokenExpiredError) { throw new factory.errors.Argument('memberOfToken', `invalid token. [${error.message} expiredAt:${error.expiredAt}]`); } else if (error instanceof jwt.JsonWebTokenError) { throw new factory.errors.Argument('memberOfToken', `invalid token. [${error.message}]`); } throw error; } return result; }); } function validateStartRequest(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; const now = params.now; const event = params.event; if (params.validateEventOfferPeriod === true) { if (typeof ((_a = params.store) === null || _a === void 0 ? void 0 : _a.id) !== 'string') { throw new factory.errors.NotFound('store.id'); } const validForMemberTierToken = (_c = (_b = params.object.reservationFor) === null || _b === void 0 ? void 0 : _b.offers) === null || _c === void 0 ? void 0 : _c.validForMemberTier; yield validateEventOfferPeriod(Object.assign({ event, now, availableAt: { id: params.store.id } }, (typeof validForMemberTierToken === 'string') ? { validForMemberTierToken } : undefined))(repos); } if (params.validateEvent === true) { validateEvent({ event, object: params.object }); } }); } function validateMemberTier(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e; const { acceptedDate, event, availableAt, verifiedValidForMemberTier, memberProgramIdentifierMustBe } = params; const tierIdentifier = (_b = (_a = verifiedValidForMemberTier.member) === null || _a === void 0 ? void 0 : _a.memberOf) === null || _b === void 0 ? void 0 : _b.identifier; const memberProgramIdentifier = (_e = (_d = (_c = verifiedValidForMemberTier.member) === null || _c === void 0 ? void 0 : _c.memberOf) === null || _d === void 0 ? void 0 : _d.isTierOf) === null || _e === void 0 ? void 0 : _e.identifier; if (typeof tierIdentifier !== 'string') { throw new factory.errors.Argument('reservationFor.offers.validForMemberTier', 'tier identifier must be string'); } if (typeof memberProgramIdentifier !== 'string') { throw new factory.errors.Argument('reservationFor.offers.validForMemberTier', 'member program must be string'); } if (memberProgramIdentifier !== memberProgramIdentifierMustBe) { throw new factory.errors.Argument('reservationFor.offers.validForMemberTier', 'member program not matched'); } // イベントオファーを検索して有効期間検証 const eventOfferForMemberTier = (yield repos.eventOffer.projectFields({ limit: 1, page: 1, project: { id: { $eq: event.project.id } }, availableAtOrFrom: { id: { $eq: availableAt.id } }, itemOffered: { id: { $eq: event.id } }, validForMemberTier: { identifier: { $eq: tierIdentifier } } }, ['validFrom', 'validThrough'])).shift(); if (eventOfferForMemberTier === undefined) { throw new factory.errors.NotFound(factory.offerType.Offer, 'event offer for member tier not found'); } let validThroughMoment; let validFromMoment; validThroughMoment = moment(eventOfferForMemberTier.validThrough, ROLE_DATE_FORMAT, true); validFromMoment = moment(eventOfferForMemberTier.validFrom, ROLE_DATE_FORMAT, true); if (acceptedDate.isBefore(validFromMoment)) { throw new factory.errors.Argument('reservationFor.offers.validForMemberTier', `the offer id valid from ${validFromMoment}`); } if (acceptedDate.isAfter(validThroughMoment)) { throw new factory.errors.Argument('reservationFor.offers.validForMemberTier', `the offer id valid through ${validThroughMoment}`); } }); } /** * イベントのオファー有効期間を検証する */ function validateEventOfferPeriod(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { var _a, _b; const { event, availableAt, validForMemberTierToken } = params; const acceptedDate = moment(params.now); const eventOffers = event.offers; // アプリケーションごとの設定を参照する(2022-11-19~) const makesOfferOnApplication = eventOffers === null || eventOffers === void 0 ? void 0 : eventOffers.seller.makesOffer.find((offer) => { var _a, _b; // support non-array(2024-10-11~) return (Array.isArray(offer.availableAtOrFrom) && ((_a = offer.availableAtOrFrom.at(0)) === null || _a === void 0 ? void 0 : _a.id) === params.availableAt.id) || (!Array.isArray(offer.availableAtOrFrom) && ((_b = offer.availableAtOrFrom) === null || _b === void 0 ? void 0 : _b.id) === params.availableAt.id); }); if (makesOfferOnApplication === undefined) { throw new factory.errors.Argument('reservationFor.id', `seller makes no available offer at ${params.availableAt.id}`); } const validFrom = makesOfferOnApplication.validFrom; const validThrough = makesOfferOnApplication.validThrough; // const validFrom = eventOffers?.validFrom; // const validThrough = eventOffers?.validThrough; if (validFrom !== undefined && validFrom !== null) { if (acceptedDate.isBefore(moment(validFrom))) { throw new factory.errors.Argument('reservationFor.id', `Offer of ${params.event.id} is valid from ${validFrom}`); } } if (validThrough !== undefined && validThrough !== null) { if (acceptedDate.isAfter(moment(validThrough))) { throw new factory.errors.Argument('reservationFor.id', `Offer of ${params.event.id} is valid through ${validThrough}`); } } // support validForMemberTier(2025-05-14~) const memberProgramIdentifierMustBe = (_b = (_a = makesOfferOnApplication.validForMemberTier) === null || _a === void 0 ? void 0 : _a.isTierOf) === null || _b === void 0 ? void 0 : _b.identifier; if (typeof memberProgramIdentifierMustBe === 'string') { if (typeof validForMemberTierToken !== 'string' || validForMemberTierToken === '') { throw new factory.errors.ArgumentNull('reservationFor.offers.validForMemberTier'); } // トークン検証 const memberProgram = (yield repos.memberProgram.projectMemberPrograms({ limit: 1, page: 1, project: { id: { $eq: params.event.project.id } }, identifier: { $eq: memberProgramIdentifierMustBe } })).shift(); if (memberProgram === undefined) { throw new factory.errors.NotFound('MemberProgram'); } const issuer = yield repos.issuer.findByIdentifier({ project: { id: params.event.project.id }, identifier: memberProgram.hostingOrganization.identifier }); if (typeof issuer.tokenSecret !== 'string' || issuer.tokenSecret === '') { throw new factory.errors.NotFound('issuer.tokenSecret'); } const verifiedValidForMemberTier = yield verifyOfferedByToken({ secret: issuer.tokenSecret, issuer: issuer.url, token: validForMemberTierToken }); yield validateMemberTier({ event, availableAt, acceptedDate, verifiedValidForMemberTier, memberProgramIdentifierMustBe })(repos); } }); } /** * イベントの上限座席数を検証する */ function validateEvent(params) { var _a, _b; // const acceptedDate = moment(params.now); const eventOffers = params.event.offers; // const validFrom = eventOffers?.validFrom; // const validThrough = eventOffers?.validThrough; // if (validFrom !== undefined && validFrom !== null) { // if (acceptedDate.isBefore(moment(validFrom))) { // throw new factory.errors.Argument( // 'reservationFor.id', // `Offer of ${params.event.id} is valid from ${validFrom}` // ); // } // } // if (validThrough !== undefined && validThrough !== null) { // if (acceptedDate.isAfter(moment(validThrough))) { // throw new factory.errors.Argument( // 'reservationFor.id', // `Offer of ${params.event.id} is valid through ${validThrough}` // ); // } // } // イベントのmaxValueを検証 const maxValue = (_a = eventOffers === null || eventOffers === void 0 ? void 0 : eventOffers.eligibleQuantity) === null || _a === void 0 ? void 0 : _a.maxValue; if (typeof maxValue === 'number') { const numAcceptedOffers = (_b = params.object.acceptedOffer) === null || _b === void 0 ? void 0 : _b.length; if (typeof numAcceptedOffers === 'number' && numAcceptedOffers > 0) { if (numAcceptedOffers > maxValue) { throw new factory.errors.Argument('reservationFor.id', `Maximum number of offers exceeded`); } } } }