import { ObjectId } from 'mongodb' import Slug from '../../functions/slug' import { DELETE, GET, POST, QRequestController, SECURE, } from './../../modules/RequestController' function CHECKPRIVATE(_: any, __: any, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value descriptor.value = function (...args: any) { const instanse = this as CustomPagesController const config = instanse.config const privateCollections = ['users', 'crm'] if (Array.isArray(config.private)) { privateCollections.push(...config.private) } const isPrivateCollection = privateCollections.includes(instanse.collection) || !instanse.collection.indexOf('system_') if (isPrivateCollection && !instanse.session?.auth) { instanse.setStatusCode(401) return null } else { return originalMethod.apply(this, args) } } } export default class CustomPagesController extends QRequestController { collection: string = '' slug: string = '' project: any = {} isUpdate: boolean = false isUpdateMany: boolean = false isCreate: boolean = false isCopy: boolean = false isDelete: boolean = false documentID: string = '' @GET @POST @DELETE _param(collection: string) { // Парсим url this.parseURL() // Назначаем контроллеру коллекцию this.collection = collection // Определяем метод if (this.isUpdate) { return this.updateDocument() } if (this.isUpdateMany) { return this.updateManyDocuments() } if (this.isCreate) { return this.createDocument() } if (this.isCopy) { return this.copyDocument() } if (this.isDelete) { return this.deleteDocument() } if (this.method === 'GET') { if (this.slug) { return this.getDocument() } else { return this.getAllDocuments() } } } parseURL() { const excludeFields = this.query?.exclude?.split(',') || [] const includeFields = this.query?.include?.split(',') || [] for (const field of excludeFields) { this.project[field] = false } for (const field of includeFields) { this.project[field] = true } this.slug = this.splittedURL[2] || '' if (this.method === 'POST' && this.splittedURL[2] === 'update') { this.isUpdate = true this.documentID = this.splittedURL[3] || '' } if (this.method === 'POST' && this.splittedURL[2] === 'updateMany') { this.isUpdateMany = true } if (this.method === 'POST' && this.splittedURL[2] === 'create') { this.isCreate = true } if (this.method === 'POST' && this.splittedURL[2] === 'copy') { this.isCopy = true this.documentID = this.splittedURL[3] || '' } if (this.method === 'DELETE') { this.isDelete = true this.documentID = this.splittedURL[2] || '' } } @CHECKPRIVATE async getDocument() { const document = await this.db.collection(this.collection).findOne( { slug: this.slug, }, { projection: this.project, } ) return document } @CHECKPRIVATE async getAllDocuments() { // определяем вводные const $ne = this.query?.$ne const limit = Number(this.query?.limit) || 0 const skip = Number(this.query?.skip) || 0 let sortQuery = null let key = null if (this.query?.sort) { sortQuery = this.query?.sort.split(':') } if (this.query?.key) { key = this.query?.key.split(':') } const find: any = {} const sort: any = {} // назначаем параметры поиска if ($ne) { find.slug = { $ne } } if (key) { let value = key[1] if (value === 'true') { value = true } if (value === 'false') { value = false } if (value === 'null') { value = null } find[key[0]] = value } if (sortQuery) { sort[sortQuery[0]] = Number(sortQuery[1]) } // Ищем const documents = await this.db .collection(this.collection) .find(find) .project(this.project) .skip(skip) .limit(limit) .sort(sort) .toArray() return documents } @SECURE() async updateDocument() { delete this.body?._id const _id = new ObjectId(this.documentID) const { value: changedDocument } = await this.db .collection(this.collection) .findOneAndUpdate( { _id }, { $set: this.body }, { returnDocument: 'after' } ) await this.saveToHistory(this.body, this.documentID, 'update') return this.answer(true, changedDocument) } async saveToHistory(original: any, id: string, type: 'update' | 'delete') { const historyCollection = this.db.collection('system_documents_history') const document = { original, documentId: id, date: new Date().toISOString(), byId: this.req?.session.auth._id, type, } await historyCollection.insertOne(document) } @SECURE() async updateManyDocuments() { for (const document of this.body) { const _id = new ObjectId(document._id) delete document._id await this.db .collection(this.collection) .updateOne({ _id }, { $set: document }) await this.saveToHistory(document, _id.toHexString(), 'update') } return this.answer(true) } @SECURE() async createDocument() { const slugFromKey = this.query?.slug || 'slug' let slug = Slug(this.body[slugFromKey] || '') if (!slug) { slug = `new-${Date.now()}` } const existDocumentWidthTheSlug = await this.db .collection(this.collection) .findOne({ slug }, { projection: { slug: true } }) if (existDocumentWidthTheSlug) { slug = `${slug}-${Date.now()}` } this.body.slug = slug this.body.createdBy = this.req?.session.auth._id const result = await this.db .collection(this.collection) .insertOne(this.body) const _id = result.insertedId this.body._id = String(_id) return { slug, doc: this.body } } @SECURE() async copyDocument() { const _id = new ObjectId(this.documentID) const origin = await this.db.collection(this.collection).findOne({ _id }) if (!origin) { return null } delete origin._id origin.slug = `${origin.slug}-${Date.now()}` origin.date = new Date().toISOString() origin.createdBy = this.req?.session.auth._id const result = ( await this.db.collection(this.collection).insertOne(origin) ) return { slug: origin.slug, doc: result.ops[0] } } @SECURE() async deleteDocument() { const _id = new ObjectId(this.documentID) await this.db.collection(this.collection).deleteOne({ _id }) const original = await this.db.collection(this.collection).findOne({ _id }) if (original) { await this.saveToHistory( JSON.parse(JSON.stringify(original)), _id.toHexString(), 'delete' ) } return this.answer(true) } }