@chevre/domain
Version:
Chevre Domain Library for Node.js
210 lines (209 loc) • 11.2 kB
JavaScript
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`);
}
}
}
}
;