Ghost/ghost/milestone-emails/lib/Milestone.js

227 lines
4.6 KiB
JavaScript
Raw Normal View History

const ObjectID = require('bson-objectid').default;
const {ValidationError} = require('@tryghost/errors');
module.exports = class Milestone {
/**
* @type {ObjectID}
*/
#id;
get id() {
return this.#id;
}
/**
* @type {'arr'|'members'}
*/
#type;
get type() {
return this.#type;
}
/** @type {number} */
#value;
get value() {
return this.#value;
}
/** @type {string} */
#currency;
get currency() {
return this.#currency;
}
/** @type {Date} */
#createdAt;
get createdAt() {
return this.#createdAt;
}
/** @type {Date|null} */
#emailSentAt;
get emailSentAt() {
return this.#emailSentAt;
}
toJSON() {
return {
id: this.id,
name: this.name,
type: this.type,
value: this.value,
currency: this.currency,
createdAt: this.createdAt,
emailSentAt: this.emailSentAt
};
}
/** @private */
constructor(data) {
this.#id = data.id;
this.#type = data.type;
this.#value = data.value;
this.#currency = data.currency;
this.#createdAt = data.createdAt;
this.#emailSentAt = data.emailSentAt;
}
/**
* @returns {string}
*/
get name() {
if (this.type === 'arr') {
return `arr-${this.value}-${this.currency}`;
}
return `members-${this.value}`;
}
/**
* @param {any} data
* @returns {Promise<Milestone>}
*/
static async create(data) {
// order of validation matters!
const id = validateId(data.id);
const type = validateType(data.type);
const currency = validateCurrency(type, data?.currency);
const value = validateValue(data.value);
const name = validateName(data.name, value, type, currency);
const emailSentAt = validateEmailSentAt(data);
/** @type Date */
let createdAt;
if (data.createdAt instanceof Date) {
createdAt = data.createdAt;
} else if (data.createdAt) {
createdAt = new Date(data.createdAt);
if (isNaN(createdAt.valueOf())) {
throw new ValidationError({
message: 'Invalid Date'
});
}
} else {
createdAt = new Date();
}
return new Milestone({
id,
name,
type,
value,
currency,
createdAt,
emailSentAt
});
}
};
/**
*
* @param {ObjectID|string|null} id
*
* @returns {ObjectID}
*/
function validateId(id) {
if (!id) {
return new ObjectID();
}
if (typeof id === 'string') {
return ObjectID.createFromHexString(id);
}
if (id instanceof ObjectID) {
return id;
}
return new ObjectID();
}
/**
*
* @param {number|null} value
*
* @returns {number}
*/
function validateValue(value) {
if (!value || typeof value !== 'number' || value === 0) {
throw new ValidationError({
message: 'Invalid value'
});
}
return value;
}
/**
*
* @param {'arr'|'members'} type
*
* @returns {string}
*/
function validateType(type) {
if (type === 'arr') {
return 'arr';
}
return 'members';
}
/**
*
* @param {'arr'|'members'} type
* @param {string|null} currency
*
* @returns {string}
*/
function validateCurrency(type, currency) {
if (type === 'members') {
return null;
}
if (!currency || (currency && typeof currency !== 'string' || currency.length > 3)) {
return 'usd';
}
return currency;
}
/**
*
* @param {string} name
* @param {number} value
* @param {'arr'|'members'} type
* @param {string|null} currency
*
* @returns {string}
*/
function validateName(name, value, type, currency) {
if (!name || !name.match(/(arr|members)-\d*/i)) {
return type === 'arr' ? `${type}-${value}-${currency}` : `${type}-${value}`;
}
return name;
}
/**
*
* @param {Object} data
* @param {Date|null} data.emailSentAt
*
* @returns {Date|null}
*/
function validateEmailSentAt(data) {
let emailSentAt;
if (data.emailSentAt instanceof Date) {
emailSentAt = data.emailSentAt;
} else if (data.emailSentAt) {
emailSentAt = new Date(data.emailSentAt);
if (isNaN(emailSentAt.valueOf())) {
throw new ValidationError({
message: 'Invalid Date'
});
}
} else {
emailSentAt = null;
}
return emailSentAt;
}