burdy
Version:
Open Source Headless Platform
526 lines (525 loc) • 19.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const auth_middleware_1 = __importDefault(require("../middleware/auth.middleware"));
const async_middleware_1 = __importDefault(require("../middleware/async.middleware"));
const typeorm_1 = require("typeorm");
const yup = __importStar(require("yup"));
const content_type_model_1 = __importDefault(require("../models/content-type.model"));
const bad_request_error_1 = __importDefault(require("../errors/bad-request-error"));
const internal_server_error_1 = __importDefault(require("../errors/internal-server-error"));
const post_model_1 = __importDefault(require("../models/post.model"));
const hooks_1 = __importDefault(require("../../shared/features/hooks"));
const mappers_1 = require("../common/mappers");
const utility_1 = require("../../admin/helpers/utility");
const content_type_bl_1 = require("../business-logic/content-type-bl");
const app = (0, express_1.default)();
app.get('/content-types', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c, _d;
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const id = (_a = req === null || req === void 0 ? void 0 : req.query) === null || _a === void 0 ? void 0 : _a.id;
const name = (_b = req === null || req === void 0 ? void 0 : req.query) === null || _b === void 0 ? void 0 : _b.name;
const search = (_c = req === null || req === void 0 ? void 0 : req.query) === null || _c === void 0 ? void 0 : _c.search;
const type = (_d = req === null || req === void 0 ? void 0 : req.query) === null || _d === void 0 ? void 0 : _d.type;
const qb = contentTypeRepository
.createQueryBuilder('contentType')
.leftJoinAndSelect('contentType.author', 'author')
.leftJoinAndSelect('author.meta', 'author.meta');
if (id) {
qb.andWhereInIds(id.split(','));
}
if (name) {
qb.andWhere('contentType.name IN (:...names)', {
names: name.split(','),
});
}
if ((search === null || search === void 0 ? void 0 : search.length) > 0) {
qb.andWhere('LOWER(contentType.name) LIKE :search', {
search: `%${search.toLowerCase()}%`,
});
}
if (type) {
qb.andWhere('contentType.type IN (:...types)', {
types: type.split(','),
});
}
const contentTypes = yield qb
.addOrderBy('contentType.updatedAt', 'DESC')
.getMany();
res.send(contentTypes.map(mappers_1.mapContentType));
})));
app.post('/content-types', (0, auth_middleware_1.default)(['content_types_create']), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _e, _f;
yield req.validate({
name: yup.string().max(256).required(),
type: yup.string().max(256).required(),
}, 'body');
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
try {
const contentType = yield contentTypeRepository.save({
name: req.body.name,
type: req.body.type,
author: (_e = req === null || req === void 0 ? void 0 : req.data) === null || _e === void 0 ? void 0 : _e.user,
fields: JSON.stringify((_f = req.body.fields) !== null && _f !== void 0 ? _f : []),
});
res.send((0, mappers_1.mapContentType)(contentType));
}
catch (err) {
if ((err === null || err === void 0 ? void 0 : err.code) === '23505') {
throw new bad_request_error_1.default('duplicate_name');
}
throw new internal_server_error_1.default('unknown_error');
}
})));
app.delete('/content-types', (0, auth_middleware_1.default)(['content_types_delete']), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _g, _h;
const ids = (_g = req === null || req === void 0 ? void 0 : req.body) !== null && _g !== void 0 ? _g : [];
if (!ids || (ids === null || ids === void 0 ? void 0 : ids.length) === 0)
return res.send([]);
const force = ((_h = req.query) === null || _h === void 0 ? void 0 : _h.force) === 'true';
const postRepository = (0, typeorm_1.getRepository)(post_model_1.default);
const postCount = yield postRepository.count({
contentTypeId: (0, typeorm_1.In)(ids),
});
if (postCount > 0 && !force)
throw new bad_request_error_1.default('posts_exist');
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const deleted = yield contentTypeRepository.delete({
id: (0, typeorm_1.In)(ids),
});
return res.send(deleted);
})));
app.put('/content-types/:contentTypeId', (0, auth_middleware_1.default)(['content_types_update']), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
yield req.validate({
name: yup.string().max(256).required(),
}, 'body');
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const contentType = yield contentTypeRepository.findOne({
relations: ['author', 'author.meta'],
where: {
id: req.params.contentTypeId,
},
});
if (!contentType)
throw new bad_request_error_1.default('invalid_content_type');
if (req.body.name) {
contentType.name = req.body.name;
}
if (req.body.fields) {
contentType.fields = JSON.stringify(req.body.fields);
}
yield contentTypeRepository.save(contentType);
res.send((0, mappers_1.mapContentType)(contentType));
})));
app.post('/content-types/import', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _j, _k;
const data = ((_j = req === null || req === void 0 ? void 0 : req.body) === null || _j === void 0 ? void 0 : _j.data) || [];
const force = (_k = req === null || req === void 0 ? void 0 : req.body) === null || _k === void 0 ? void 0 : _k.force;
const filtered = data.filter((contentType) => {
return (!(0, utility_1.isEmptyString)(contentType.name) && !(0, utility_1.isEmptyString)(contentType.type));
});
const entityManager = (0, typeorm_1.getManager)();
let response = [];
yield entityManager.transaction((transactionManager) => __awaiter(void 0, void 0, void 0, function* () {
var _l;
response = yield (0, content_type_bl_1.importContentTypes)({
entityManager: transactionManager,
data: filtered,
user: (_l = req === null || req === void 0 ? void 0 : req.data) === null || _l === void 0 ? void 0 : _l.user,
options: {
force,
},
});
}));
res.send(response);
})));
app.get('/content-types/export', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _m;
const ids = (((_m = req === null || req === void 0 ? void 0 : req.query) === null || _m === void 0 ? void 0 : _m.id) || '').split(',');
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const contentTypes = yield contentTypeRepository.find({
where: {
id: (0, typeorm_1.In)(ids),
},
});
const mapped = contentTypes.map((contentType) => {
let fields = [];
try {
fields = JSON.parse(contentType.fields);
}
catch (_a) {
//
}
return {
name: contentType === null || contentType === void 0 ? void 0 : contentType.name,
type: contentType === null || contentType === void 0 ? void 0 : contentType.type,
fields,
};
});
res.setHeader('Content-disposition', `attachment; filename=contentTypes.json`);
res.setHeader('Content-type', 'application/json');
res.send(mapped);
})));
app.get('/content-types/single', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _o;
const name = (_o = req === null || req === void 0 ? void 0 : req.query) === null || _o === void 0 ? void 0 : _o.name;
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const qb = contentTypeRepository
.createQueryBuilder('contentType')
.leftJoinAndSelect('contentType.author', 'author')
.leftJoinAndSelect('author.meta', 'author.meta');
if (name) {
qb.andWhere('contentType.name = :name', {
name,
});
}
const contentType = yield qb.getOne();
if (!contentType)
throw new bad_request_error_1.default('invalid_content_type');
res.send((0, mappers_1.mapContentType)(contentType));
})));
app.get('/content-types/:contentTypeId', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const contentType = yield contentTypeRepository.findOne({
id: req.params.contentTypeId,
});
if (!contentType)
throw new bad_request_error_1.default('invalid_content_type');
res.send((0, mappers_1.mapContentType)(contentType));
})));
// Content types
const fields = [
{
type: 'richtext',
name: 'Rich Text',
component: './richtext.tsx',
iconProps: { iconName: 'FabricTextHighlight' },
group: 'Core',
},
{
type: 'number',
name: 'Number',
iconProps: { iconName: 'NumberField' },
group: 'Core',
fields: [
{
name: 'required',
type: 'checkbox',
label: 'Required',
},
{
name: 'defaultValue',
type: 'number',
label: 'Default',
},
],
},
{
type: 'choicegroup',
name: 'Choice Group',
iconProps: { iconName: 'RadioBtnOn' },
group: 'Core',
fields: [
{
name: 'options',
type: 'text',
multiline: true,
placeholder: 'green\nred\nblue',
label: 'Options',
},
{
name: 'defaultValue',
type: 'text',
label: 'Default',
},
],
},
{
type: 'dropdown',
name: 'Dropdown',
iconProps: { iconName: 'Dropdown' },
group: 'Core',
fields: [
{
name: 'options',
type: 'text',
multiline: true,
placeholder: 'green\nred\nblue',
label: 'Options',
},
{
name: 'defaultValue',
type: 'text',
label: 'Default',
},
{
name: 'multiSelect',
type: 'checkbox',
label: 'Multi Select',
},
],
},
{
type: 'checkbox',
name: 'Checkbox',
iconProps: { iconName: 'CheckboxComposite' },
group: 'Core',
fields: [
{
name: 'defaultValue',
type: 'choicegroup',
defaultValue: 'false',
label: 'Default',
options: 'true\nfalse',
},
],
},
{
type: 'colorpicker',
name: 'Color Picker',
iconProps: { iconName: 'Eyedropper' },
group: 'Core',
},
{
type: 'datepicker',
name: 'Date Picker',
iconProps: { iconName: 'CalendarWeek' },
group: 'Core',
},
{
type: 'images',
name: 'Images',
iconProps: { iconName: 'FileImage' },
group: 'Core',
fields: [
{
name: 'multiSelect',
type: 'checkbox',
label: 'Multi Select',
},
],
},
{
type: 'assets',
name: 'Assets',
iconProps: { iconName: 'Document' },
group: 'Core',
fields: [
{
name: 'multiSelect',
type: 'checkbox',
label: 'Multi Select',
},
],
},
{
type: 'relation',
name: 'Relation',
description: 'Deprecated - use reference instead',
iconProps: { iconName: 'Relationship' },
group: 'Core',
fields: [
{
type: 'post_type_dropdown',
name: 'posts',
multiSelect: true,
label: 'Allowed post types',
rules: {
required: 'Field is required',
},
},
],
},
{
type: 'reference_single',
name: 'Reference - Single',
iconProps: { iconName: 'Relationship' },
group: 'Core',
fields: [
{
type: 'post_type_dropdown',
name: 'posts',
multiSelect: true,
label: 'Allowed post types',
},
],
},
{
type: 'reference_multiple',
name: 'Reference - Multiple',
iconProps: { iconName: 'Relationship' },
group: 'Core',
fields: [
{
type: 'post_type_dropdown',
name: 'posts',
multiSelect: true,
label: 'Allowed post types',
},
],
},
{
type: 'group',
name: 'Group',
iconProps: { iconName: 'ViewListTree' },
group: 'Layout',
},
{
type: 'repeatable',
name: 'Repeatable',
iconProps: { iconName: 'ViewList' },
group: 'Layout',
fields: [
{
name: 'max',
type: 'number',
label: 'Maximum Items',
},
],
},
{
type: 'tab',
name: 'Tab',
iconProps: { iconName: 'TabCenter' },
group: 'Layout',
},
{
type: 'zone',
name: 'Dynamic Zone',
iconProps: { iconName: 'Add' },
group: 'Layout',
fields: [
{
type: 'components_dropdown',
name: 'components',
label: 'Allowed components',
multiSelect: true,
rules: {
required: 'Field is required',
},
},
],
},
{
type: 'custom',
name: 'Custom Component',
iconProps: { iconName: 'Add' },
group: 'Core',
fields: [
{
name: 'allowToggle',
type: 'checkbox',
label: 'Allow Toggle',
},
{
type: 'components_dropdown',
name: 'component',
label: 'Component',
rules: {
required: 'Field is required',
},
},
],
},
{
type: 'text',
name: 'Text',
iconProps: { iconName: 'TextField' },
group: 'Core',
fields: [
{
name: 'required',
type: 'checkbox',
label: 'Required',
},
{
name: 'defaultValue',
type: 'text',
label: 'Default',
},
{
name: 'multiline',
type: 'checkbox',
label: 'Multiline',
},
],
},
{
type: 'text-editor',
name: 'Text Editor (Ace)',
iconProps: { iconName: 'NumberSymbol' },
group: 'Core',
fields: [
{
name: 'mode',
type: 'choicegroup',
defaultValue: 'json',
label: 'Type',
required: true,
options: 'json\nxml\nyaml\njavascript\ntypescript\ntext\nhtml\ncss\nsql\nmarkdown\nsh',
},
],
},
];
const mapComponent = (component) => {
return {
id: component.id,
name: component.name,
type: 'component',
group: 'Custom Components',
};
};
app.get('/components', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
const contentTypeRepository = (0, typeorm_1.getRepository)(content_type_model_1.default);
const contentTypes = yield contentTypeRepository.find({
type: 'component',
});
res.send(contentTypes.map(mapComponent));
})));
app.get('/fields', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
const allFields = yield hooks_1.default.applyFilters('contentType/fields', [
...fields,
]);
res.send(allFields);
})));
app.get('/fields/:fieldType', (0, auth_middleware_1.default)(), (0, async_middleware_1.default)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
const allFields = yield hooks_1.default.applyFilters('contentType/fields', [
...fields,
]);
const field = allFields.find((field) => field.type === req.params.fieldType);
if (!field)
throw new bad_request_error_1.default('invalid_field_type');
res.send(field);
})));
exports.default = app;