257 lines
8.5 KiB
JavaScript
257 lines
8.5 KiB
JavaScript
|
"use strict";
|
||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
|
};
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.Collection = void 0;
|
||
|
const errors_1 = require("@tryghost/errors");
|
||
|
const tpl_1 = __importDefault(require("@tryghost/tpl"));
|
||
|
const nql_1 = __importDefault(require("@tryghost/nql"));
|
||
|
const nql_filter_expansions_1 = require("@tryghost/nql-filter-expansions");
|
||
|
const CollectionPostAdded_1 = require("./events/CollectionPostAdded");
|
||
|
const CollectionPostRemoved_1 = require("./events/CollectionPostRemoved");
|
||
|
const bson_objectid_1 = __importDefault(require("bson-objectid"));
|
||
|
const messages = {
|
||
|
invalidIDProvided: 'Invalid ID provided for Collection',
|
||
|
invalidDateProvided: 'Invalid date provided for {fieldName}',
|
||
|
invalidFilterProvided: {
|
||
|
message: 'Invalid filter provided for automatic Collection',
|
||
|
context: 'Automatic type of collection should always have a filter value'
|
||
|
},
|
||
|
noTitleProvided: 'Title must be provided',
|
||
|
slugMustBeUnique: 'Slug must be unique'
|
||
|
};
|
||
|
function validateFilter(filter, type, isAllowedEmpty = false) {
|
||
|
const allowedProperties = ['featured', 'published_at', 'tag', 'tags'];
|
||
|
if (type === 'manual') {
|
||
|
if (filter !== null) {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidFilterProvided.message),
|
||
|
context: (0, tpl_1.default)(messages.invalidFilterProvided.context)
|
||
|
});
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
// type === 'automatic' now
|
||
|
if (filter === null) {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidFilterProvided.message),
|
||
|
context: (0, tpl_1.default)(messages.invalidFilterProvided.context)
|
||
|
});
|
||
|
}
|
||
|
if (filter.trim() === '' && !isAllowedEmpty) {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidFilterProvided.message),
|
||
|
context: (0, tpl_1.default)(messages.invalidFilterProvided.context)
|
||
|
});
|
||
|
}
|
||
|
try {
|
||
|
const parsedFilter = (0, nql_1.default)(filter);
|
||
|
const keysUsed = [];
|
||
|
nql_1.default.utils.mapQuery(parsedFilter.toJSON(), function (value, key) {
|
||
|
keysUsed.push(key);
|
||
|
});
|
||
|
if (keysUsed.some(key => !allowedProperties.includes(key))) {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidFilterProvided.message)
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidFilterProvided.message)
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
class Collection {
|
||
|
events;
|
||
|
id;
|
||
|
title;
|
||
|
_slug;
|
||
|
get slug() {
|
||
|
return this._slug;
|
||
|
}
|
||
|
async setSlug(slug, uniqueChecker) {
|
||
|
if (slug === this.slug) {
|
||
|
return;
|
||
|
}
|
||
|
if (await uniqueChecker.isUniqueSlug(slug)) {
|
||
|
this._slug = slug;
|
||
|
}
|
||
|
else {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.slugMustBeUnique)
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
description;
|
||
|
type;
|
||
|
_filter;
|
||
|
get filter() {
|
||
|
return this._filter;
|
||
|
}
|
||
|
set filter(value) {
|
||
|
if (this.slug === 'latest' || this.slug === 'featured') {
|
||
|
return;
|
||
|
}
|
||
|
validateFilter(value, this.type);
|
||
|
this._filter = value;
|
||
|
}
|
||
|
featureImage;
|
||
|
createdAt;
|
||
|
updatedAt;
|
||
|
get deletable() {
|
||
|
return this.slug !== 'latest' && this.slug !== 'featured';
|
||
|
}
|
||
|
_deleted = false;
|
||
|
_posts;
|
||
|
get posts() {
|
||
|
return this._posts;
|
||
|
}
|
||
|
get deleted() {
|
||
|
return this._deleted;
|
||
|
}
|
||
|
set deleted(value) {
|
||
|
if (this.deletable) {
|
||
|
this._deleted = value;
|
||
|
}
|
||
|
}
|
||
|
postMatchesFilter(post) {
|
||
|
const filterNql = (0, nql_1.default)(this.filter, {
|
||
|
expansions: nql_filter_expansions_1.posts
|
||
|
});
|
||
|
return filterNql.queryJSON(post);
|
||
|
}
|
||
|
/**
|
||
|
* @param post {{id: string}} - The post to add to the collection
|
||
|
* @param index {number} - The index to insert the post at, use negative numbers to count from the end.
|
||
|
*/
|
||
|
addPost(post, index = -0) {
|
||
|
if (this.slug === 'latest') {
|
||
|
return false;
|
||
|
}
|
||
|
if (this.type === 'automatic') {
|
||
|
const matchesFilter = this.postMatchesFilter(post);
|
||
|
if (!matchesFilter) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
if (this.posts.includes(post.id)) {
|
||
|
this._posts = this.posts.filter(id => id !== post.id);
|
||
|
}
|
||
|
else {
|
||
|
this.events.push(CollectionPostAdded_1.CollectionPostAdded.create({
|
||
|
post_id: post.id,
|
||
|
collection_id: this.id
|
||
|
}));
|
||
|
}
|
||
|
if (index < 0 || Object.is(index, -0)) {
|
||
|
index = this.posts.length + index;
|
||
|
}
|
||
|
this.posts.splice(index, 0, post.id);
|
||
|
return true;
|
||
|
}
|
||
|
removePost(id) {
|
||
|
if (this.posts.includes(id)) {
|
||
|
this._posts = this.posts.filter(postId => postId !== id);
|
||
|
this.events.push(CollectionPostRemoved_1.CollectionPostRemoved.create({
|
||
|
post_id: id,
|
||
|
collection_id: this.id
|
||
|
}));
|
||
|
}
|
||
|
}
|
||
|
includesPost(id) {
|
||
|
return this.posts.includes(id);
|
||
|
}
|
||
|
removeAllPosts() {
|
||
|
for (const id of this._posts) {
|
||
|
this.events.push(CollectionPostRemoved_1.CollectionPostRemoved.create({
|
||
|
post_id: id,
|
||
|
collection_id: this.id
|
||
|
}));
|
||
|
}
|
||
|
this._posts = [];
|
||
|
}
|
||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||
|
constructor(data) {
|
||
|
this.id = data.id;
|
||
|
this.title = data.title;
|
||
|
this._slug = data.slug;
|
||
|
this.description = data.description;
|
||
|
this.type = data.type;
|
||
|
this._filter = data.filter;
|
||
|
this.featureImage = data.featureImage;
|
||
|
this.createdAt = data.createdAt;
|
||
|
this.updatedAt = data.updatedAt;
|
||
|
this.deleted = data.deleted;
|
||
|
this._posts = data.posts;
|
||
|
this.events = [];
|
||
|
}
|
||
|
toJSON() {
|
||
|
return {
|
||
|
id: this.id,
|
||
|
title: this.title,
|
||
|
slug: this.slug,
|
||
|
description: this.description,
|
||
|
type: this.type,
|
||
|
filter: this.filter,
|
||
|
featureImage: this.featureImage,
|
||
|
createdAt: this.createdAt,
|
||
|
updatedAt: this.updatedAt,
|
||
|
posts: this.posts
|
||
|
};
|
||
|
}
|
||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||
|
static validateDateField(date, fieldName) {
|
||
|
if (!date) {
|
||
|
return new Date();
|
||
|
}
|
||
|
if (date instanceof Date) {
|
||
|
return date;
|
||
|
}
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidDateProvided, { fieldName })
|
||
|
});
|
||
|
}
|
||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||
|
static async create(data) {
|
||
|
let id;
|
||
|
if (!data.id) {
|
||
|
id = new bson_objectid_1.default();
|
||
|
}
|
||
|
else if (typeof data.id === 'string') {
|
||
|
id = bson_objectid_1.default.createFromHexString(data.id);
|
||
|
}
|
||
|
else if (data.id instanceof bson_objectid_1.default) {
|
||
|
id = data.id;
|
||
|
}
|
||
|
else {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.invalidIDProvided)
|
||
|
});
|
||
|
}
|
||
|
const type = data.type === 'automatic' ? 'automatic' : 'manual';
|
||
|
const filter = typeof data.filter === 'string' ? data.filter : null;
|
||
|
validateFilter(filter, type, data.slug === 'latest');
|
||
|
if (!data.title) {
|
||
|
throw new errors_1.ValidationError({
|
||
|
message: (0, tpl_1.default)(messages.noTitleProvided)
|
||
|
});
|
||
|
}
|
||
|
return new Collection({
|
||
|
id: id.toHexString(),
|
||
|
title: data.title,
|
||
|
slug: data.slug,
|
||
|
description: data.description || null,
|
||
|
type: type,
|
||
|
filter: filter,
|
||
|
featureImage: data.feature_image || null,
|
||
|
createdAt: Collection.validateDateField(data.created_at, 'created_at'),
|
||
|
updatedAt: Collection.validateDateField(data.updated_at, 'updated_at'),
|
||
|
deleted: data.deleted || false,
|
||
|
posts: data.slug !== 'latest' ? (data.posts || []) : []
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
exports.Collection = Collection;
|
||
|
//# sourceMappingURL=Collection.js.map
|