@prisma-cms/resource-module
Version:
Resource module for prisma-cms
601 lines (385 loc) • 11.4 kB
JavaScript
import fs from "fs";
import chalk from "chalk";
import PrismaModule from "@prisma-cms/prisma-module";
import LogModule from "@prisma-cms/log-module";
// import UploadModule from "@prisma-cms/upload-module";
import PrismaProcessor from "@prisma-cms/prisma-processor";
import MergeSchema from 'merge-graphql-schemas';
import path from 'path';
const moduleURL = new URL(import.meta.url);
const __dirname = path.dirname(moduleURL.pathname);
const { createWriteStream, unlinkSync } = fs;
const { fileLoader, mergeTypes } = MergeSchema
import Translit from "translit";
import TranslitRussian from "translit-russian";
import URI from "urijs";
export class ResourceProcessor extends PrismaProcessor {
constructor(props) {
super(props);
this.objectType = "Resource";
this.private = true;
this.ownable = true;
}
async create(method, args, info) {
const {
ctx,
} = this;
const {
getProjectFromRequest,
} = ctx;
let {
data: {
name,
uri,
PrismaProject,
...data
},
} = args;
let uriData = await this.prepareUri(args);
/**
* Пытаемся получить проект по заголовкам запроса.
* Если получим, то устанавливаем в качестве проекта.
* Если нет, то сбрасываем.
*/
const project = await getProjectFromRequest(ctx);
if (project) {
const {
id: projectId,
} = project;
PrismaProject = {
connect: {
id: projectId,
},
}
}
else {
PrismaProject = undefined;
}
// console.log("PrismaProject", PrismaProject);
Object.assign(data, {
PrismaProject,
...uriData,
// ...this.getCreatedBy(),
});
Object.assign(args, {
data,
});
// return this.addFieldError("test", "error");
if (!data.uri) {
return this.addError("Не был сформирован uri документа");
}
return super.create(method, args, info);
}
async update(method, args, info) {
let {
data: {
// Запрещаем обновление проекта
PrismaProject,
...data
},
} = args;
Object.assign(data, {
});
Object.assign(args, {
data,
});
return super.update(method, args, info);
}
async mutate(method, args, info) {
if (args.data) {
let {
name,
content,
contentText,
...data
} = args.data || {};
this.prepareContent(args, data, method);
name = this.prepareName(args);
Object.assign(data, {
name,
});
Object.assign(args, {
data,
});
// console.log('ResourceProcessor data', JSON.stringify(data, true, 2));
}
return super.mutate(method, args);
}
prepareContent(args, data, method) {
let {
data: {
content,
},
} = args;
if (content !== undefined) {
const {
blocks,
} = content || {};
let textArray = blocks && blocks.map(({ text }) => text && text.trim() || "").filter(n => n) || [];
let contentText = textArray.join(" ");
Object.assign(data, {
content,
contentText,
});
}
// console.log(chalk.green("prepareContent content"), typeof content, content, data);
// this.addError("Sdfsdfsdf");
return data;
}
// getCreatedBy() {
// const {
// currentUser,
// } = this.ctx;
// if (!currentUser) {
// this.addError("Необходимо авторизоваться");
// return;
// }
// const {
// id,
// } = currentUser;
// return {
// CreatedBy: {
// connect: {
// id,
// },
// },
// }
// }
prepareName(args) {
let {
data: {
name,
},
} = args;
if (name !== undefined) {
name = name && name.trim() || null;
if (!name) {
this.addFieldError("name", "Не заполнено название");
}
}
return name;
}
async prepareUri(args, cycles = 10) {
const {
db,
} = this.ctx;
let {
data: {
name,
uri,
isfolder = true,
Parent,
},
} = args;
// console.log(chalk.green("prepareUri uri"), uri);
name = this.prepareName(args);
/**
* Если нет УРИ, генерируем из родителя и алиаса.
* При этом надо проверять на уникальность
*/
if (!uri) {
uri = new URI(this.escapeUri(name));
if (Parent && Parent.connect) {
let parent = await db.query.resource({
where: Parent.connect,
});
if (parent) {
let parentUri = new URI(parent.uri);
// let parentDirname;
// let parentFilename = parentUri.filename();
// if(parentFilename){
// parentDirname
// }
// this.addFieldError("test parentFilename", parentFilename);
parentUri.suffix("");
// this.addFieldError("test parentUri", parentUri.path());
uri.directory(parentUri.path());
// this.addFieldError("test uri", uri.toString());
}
else {
throw new Error("Can not get parent resource");
}
}
uri = uri.toString();
}
if (uri !== undefined) {
uri = this.translit(uri.trim()).replace(/[\?\# ]+/g, '-').toLowerCase();
uri = new URI(uri);
// console.log(chalk.green("URL"), uri);
let segment = uri.segment();
// console.log(chalk.green("segment"), segment);
segment = segment.map(n => this.escapeUri(n).replace(/^\-+|\-$/g, '').trim()).filter(n => n);
// console.log(chalk.green("segment 2"), segment);
uri.segment(segment);
let pathname = uri.pathname();
if (!pathname.startsWith("/")) {
pathname = `/${pathname}`;
}
if (!isfolder) {
let suffix = uri.suffix()
if (!suffix) {
this.addSuffix(uri);
}
}
else {
if (!pathname.endsWith("/")) {
pathname = `${pathname}/`;
}
}
uri.pathname(pathname);
// Проверяем на уникальность
const exists = await db.exists.Resource({
uri: uri.toString(),
});
if (exists) {
if (cycles === 0) {
this.addFieldError("uri", "Ошибка генерации уникального УРЛ. Превышено количество попыток.");
return;
}
// console.log(chalk.green("exists uri"), uri);
// this.addFieldError("uri", "test");
// return this.prepareUri(args);
let filename = uri.filename();
if (!filename) {
this.addFieldError("uri", "Ошибка генерации уникального УРЛ");
}
else {
let suffix = uri.suffix();
if (suffix) {
uri.suffix("");
filename = uri.filename();
// console.log(chalk.green("Resulted filename 2"), filename);
}
// console.log(chalk.green("Resulted match"), match);
let reg = /(\-(\d+)|)$/;
let match = filename.match(reg);
let index = match && parseInt(match[2]) || 0;
filename = filename.replace(reg, `-${index + 1}`);
uri.filename(filename);
Object.assign(args.data, {
uri: uri.toString(),
});
return this.prepareUri(args, cycles > 0 ? cycles-- : cycles);
}
}
uri = URI.decode(uri.toString());
}
// console.log(chalk.green("Resulted uri"), uri);
return {
name,
uri,
isfolder,
};
}
addSuffix(uri) {
uri.suffix("html");
}
translit(word) {
const translit = Translit(TranslitRussian);
return translit(word);
}
escapeUri(uri) {
return uri ? uri.replace(/[\/\?\% ]+/g, '-').replace(/\-+/g, '-') : "";
}
}
class Module extends PrismaModule {
constructor(props = {}) {
super(props);
this.mergeModules([
LogModule,
// UploadModule,
]);
}
getSchema(types = []) {
let schema = fileLoader(__dirname + '/schema/database/', {
recursive: true,
});
if (schema) {
types = types.concat(schema);
}
let typesArray = super.getSchema(types);
return typesArray;
}
getApiSchema(types = []) {
let baseSchema = [];
let schemaFile = __dirname + "/../schema/generated/prisma.graphql";
if (fs.existsSync(schemaFile)) {
baseSchema = fs.readFileSync(schemaFile, "utf-8");
}
let apiSchema = super.getApiSchema(types.concat(baseSchema), [
// "ResourceCreateInput",
// "ResourceUpdateInput",
// "UserCreateOneWithoutResourcesInput",
// "ResourceCreateOneWithoutChildsInput",
// "ResourceCreateManyWithoutParentInput",
// "UserUpdateOneWithoutResourcesInput",
// "ResourceUpdateOneWithoutChildsInput",
// "ResourceUpdateManyWithoutParentInput",
// "ResourceUpdateManyWithoutCreatedByInput",
// "ResourceCreateManyWithoutCreatedByInput",
// "FileCreateOneWithoutImageResourceInput",
// "FileUpdateOneWithoutImageResourceInput",
]);
let schema = fileLoader(__dirname + '/schema/api/', {
recursive: true,
});
apiSchema = mergeTypes([apiSchema.concat(schema)], { all: true });
return apiSchema;
}
getResolvers() {
const resolvers = super.getResolvers();
Object.assign(resolvers.Query, {
resource: this.resource,
resources: this.resources,
resourcesConnection: this.resourcesConnection,
});
Object.assign(resolvers.Mutation, {
createResourceProcessor: this.createResourceProcessor.bind(this),
updateResourceProcessor: this.updateResourceProcessor.bind(this),
deleteResource: (source, args, ctx, info) => {
return this.getProcessor(ctx).delete("Resource", args, info);
},
});
// Object.assign(resolvers.Subscription, this.Subscription);
Object.assign(resolvers, {
ResourceResponse: this.ResourceResponse(),
});
return resolvers;
}
resources(source, args, ctx, info) {
return ctx.db.query.resources(args, info);
}
resource(source, args, ctx, info) {
return ctx.db.query.resource(args, info);
}
resourcesConnection(source, args, ctx, info) {
return ctx.db.query.resourcesConnection(args, info);
}
getProcessor(ctx) {
return new (this.getProcessorClass())(ctx);
}
getProcessorClass() {
return ResourceProcessor;
}
createResourceProcessor(source, args, ctx, info) {
return this.getProcessor(ctx).createWithResponse("Resource", args, info);
}
updateResourceProcessor(source, args, ctx, info) {
return this.getProcessor(ctx).updateWithResponse("Resource", args, info);
}
ResourceResponse() {
return {
data: (source, args, ctx, info) => {
const {
id,
} = source.data || {};
return id ? ctx.db.query.resource({
where: {
id,
},
}, info) : null;
}
}
}
}
export default Module;