@kohanajs/mod-cms
Advanced tools
Comparing version 4.0.0 to 4.2.0
@@ -5,2 +5,18 @@ # Changelog | ||
## [4.2.0](https://gitlab.com/kohana-js/proposals/level0/mod-cms/compare/v4.1.0...v4.2.0) (2021-11-30) | ||
### Features | ||
* page blocks ([f29de7f](https://gitlab.com/kohana-js/proposals/level0/mod-cms/commit/f29de7fee2b073c837801156c3367bc40be5b95b)) | ||
## [4.1.0](https://gitlab.com/kohana-js/proposals/level0/mod-cms/compare/v4.0.1...v4.1.0) (2021-11-08) | ||
### Features | ||
* unpublish on delete ([2ad52eb](https://gitlab.com/kohana-js/proposals/level0/mod-cms/commit/2ad52eb2a8cc57a53e3de3351e6e492ca0dccc92)) | ||
### [4.0.1](https://gitlab.com/kohana-js/proposals/level0/mod-cms/compare/v4.0.0...v4.0.1) (2021-11-08) | ||
## [4.0.0](https://gitlab.com/kohana-js/proposals/level0/mod-cms/compare/v3.2.0...v4.0.0) (2021-11-08) | ||
@@ -7,0 +23,0 @@ |
@@ -1,8 +0,8 @@ | ||
const {SQL} = require("@kohanajs/constants"); | ||
const path = require('path'); | ||
const {readFile} = require('fs').promises; | ||
const {ControllerMixinMultipartForm, HelperForm} = require("@kohanajs/mod-form"); | ||
const {ControllerMixinDatabase, ControllerMixinView, ORMAdapter, KohanaJS, ORM} = require("kohanajs"); | ||
const {ControllerAdmin} = require("@kohanajs/mod-admin"); | ||
const Page = ORM.require('Page'); | ||
const PageItem = ORM.require('PageItem'); | ||
const PageItemValue = ORM.require('PageItemValue'); | ||
const pluralize = require('pluralize'); | ||
@@ -67,6 +67,6 @@ | ||
async action_create_by_type(){ | ||
const { draftDB, page_type } = await this.assignDatabase(); | ||
const { draftDB: database, page_type } = await this.assignDatabase(); | ||
const insertID = ORMAdapter.defaultID(); | ||
const page = ORM.create(Page, {database: draftDB, insertID}); | ||
const page = ORM.create(Page, {database, insertID}); | ||
page.name = `Untitled ${pluralize.singular(page_type)}`; | ||
@@ -80,54 +80,19 @@ page.page_type = page_type; | ||
async action_page_add_item(){ | ||
const pageId = this.request.params['page_id']; | ||
const itemName= this.request.params['item_name']; | ||
async action_import_post(){ | ||
const $_POST = this.state.get(ControllerMixinMultipartForm.POST_DATA); | ||
const uploadRoot = `${KohanaJS.EXE_PATH}/../public`; | ||
const file = await HelperForm.moveToUpload($_POST['import_file'], '/media/import', uploadRoot); | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const page = await ORM.factory(Page, pageId, {database}); | ||
if(!page) throw new Error(`Page ${pageId} not found`); | ||
const buffer = await readFile(path.normalize(uploadRoot + file)); | ||
const text = buffer.toString('ucs2'); | ||
const pageItems = await ORM.readWith(PageItem, [ | ||
['', 'page_id', SQL.EQUAL, page.id], | ||
[SQL.AND, 'name', SQL.EQUAL, itemName] | ||
], {database, asArray:true}); | ||
const data = text | ||
.replace(/^\uFEFF/, '') | ||
.replaceAll('\r\n', '\n') | ||
.split('\n'); | ||
const headers = data.shift().split('\t').map(it => it.toLowerCase()); | ||
const masterItem = pageItems.filter(it => it.weight === 1)[0] || pageItems[0]; | ||
await masterItem.eagerLoad({with: ['PageItemValue']}); | ||
const template = masterItem.page_item_values; | ||
if(!template.length)throw new Error(`PageItem ${masterItem} is empty and cannot be copy`); | ||
const newPageItem = ORM.create(PageItem, {database}); | ||
newPageItem.page_id = page.id; | ||
newPageItem.page_version_id = masterItem.page_version_id; | ||
newPageItem.name = masterItem.name; | ||
newPageItem.weight = pageItems.length + 1; | ||
await newPageItem.write(); | ||
await Promise.all( | ||
template.map(async itemValue => { | ||
const newValue = ORM.create(PageItemValue, {database}); | ||
newValue.page_item_id = newPageItem.id; | ||
newValue.language_id = itemValue.language_id; | ||
newValue.name = itemValue.name; | ||
newValue.attribute_name = itemValue.attribute_name; | ||
newValue.value = ''; | ||
await newValue.write(); | ||
}) | ||
); | ||
await this.redirect(`/admin/pages/${page.id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
async action_page_delete_item(){ | ||
const item_id = this.request.params['item_id']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const item = await ORM.factory(PageItem, item_id, {database}); | ||
const page_id = item.page_id; | ||
await item.delete(); | ||
await this.redirect(`/admin/pages/${page_id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
} | ||
module.exports = ControllerAdminContent; |
@@ -0,7 +1,8 @@ | ||
const {SQL} = require("@kohanajs/constants"); | ||
const path = require('path'); | ||
const {stat, mkdir, copyFile, unlink} = require('fs').promises; | ||
const { ControllerAdmin } = require('@kohanajs/mod-admin'); | ||
const { ControllerMixinDatabase, ControllerMixinView, KohanaJS, ORM } = require('kohanajs'); | ||
const { ControllerMixinMultipartForm } = require('@kohanajs/mod-form'); | ||
const { ControllerMixinORMDelete } = require("@kohanajs/mixin-orm"); | ||
const { ControllerMixinMultipartForm, HelperForm } = require('@kohanajs/mod-form'); | ||
const HelperPage = require('../../helper/Page'); | ||
@@ -11,2 +12,9 @@ | ||
const Language = ORM.require('Language'); | ||
const PageItem = ORM.require('PageItem'); | ||
const PageItemValue = ORM.require('PageItemValue'); | ||
const PageBlock = ORM.require('PageBlock'); | ||
const PageBlockAttribute = ORM.require('PageBlockAttribute'); | ||
const PageBlockValue = ORM.require('PageBlockValue'); | ||
const PageBlockItem = ORM.require('PageBlockItem'); | ||
const PageBlockItemValue = ORM.require('PageBlockItemValue'); | ||
@@ -34,26 +42,2 @@ class ControllerAdminPage extends ControllerAdmin { | ||
async moveToUpload(fileField){ | ||
const today = new Date(); | ||
const uploadFolder = `${KohanaJS.EXE_PATH}/../public`; | ||
const dateFolder = `/media/cms/${today.getFullYear()}/${today.getMonth()+1}/${today.getDate()}`; | ||
const uploadDateFolder = path.normalize(uploadFolder+dateFolder); | ||
//create folder | ||
try{ | ||
await stat(uploadDateFolder) | ||
}catch(err){ | ||
if(err.code === 'ENOENT'){ | ||
await mkdir(uploadDateFolder, {recursive: true}); | ||
}else{ | ||
throw err; | ||
} | ||
} | ||
const uploadPath = `${dateFolder}/${fileField.tmpName}-${fileField.filename}`; | ||
//move file to media/upload | ||
await copyFile(fileField.tmp, path.normalize(uploadFolder + uploadPath)); | ||
await unlink(fileField.tmp); | ||
return uploadPath; | ||
} | ||
async action_update() { | ||
@@ -66,5 +50,2 @@ //if no param id, create page proxy | ||
//find page type name | ||
await HelperPage.defaultValue(instance, instance.page_type, database, this.languageId); | ||
const $_POST = this.state.get(ControllerMixinMultipartForm.POST_DATA); | ||
@@ -76,4 +57,4 @@ //handle files upload | ||
//move tmp file to public/media/upload | ||
const id = key.match(/\((\d+)\)/)[1]; | ||
const Model = key.match(/>([^(]+)/)[1]; | ||
const id = key.match(/\((\d+)\):value/)[1]; | ||
const Model = key.match(/>([^(]+)\(\d+\):value/)[1]; | ||
@@ -88,3 +69,3 @@ const instance = await ORM.factory(ORM.require(Model), id, {database}); | ||
} | ||
instance.value = await this.moveToUpload($_POST[key]); | ||
instance.value = await HelperForm.moveToUpload($_POST[key], '/media/cms', `${KohanaJS.EXE_PATH}/../public`); | ||
await instance.write(); | ||
@@ -95,2 +76,3 @@ } | ||
this.request.session.autosave = $_POST['autosave']; | ||
@@ -131,3 +113,3 @@ switch ($_POST['action']) { | ||
//check page exist, remove it. | ||
const exist = await ORM.readBy(Page, 'id', [page.id],{database, limit:1, asArray:false}); | ||
const exist = await ORM.factory(Page, page.id, {database}); | ||
if(exist)await exist.delete(); | ||
@@ -170,9 +152,16 @@ | ||
async action_unpublish(){ | ||
async unpublish(){ | ||
const id = this.request.params['id']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('live'); | ||
const exist = await ORM.factory(Page, id,{database}); | ||
if(!exist)throw new Error(`Page not published`); | ||
await exist.delete(); | ||
try{ | ||
const exist = await ORM.factory(Page, id,{database}); | ||
await exist.delete(); | ||
} catch (e){ | ||
} | ||
} | ||
async action_unpublish(){ | ||
await this.unpublish(); | ||
const draftDB = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
@@ -186,17 +175,13 @@ const page = await ORM.factory(Page, id, {database: draftDB}); | ||
async setEditTemplate(){ | ||
setEditTemplate(page, placeholders = {}){ | ||
const templateData = this.state.get(ControllerMixinView.TEMPLATE).data; | ||
const page = this.state.get('instance'); | ||
await page.eagerLoad({ | ||
with:["PageValue", "PageAttribute", "PageItem", "PageBlock"], | ||
page_items: {with: ['PageItemValue']}, | ||
page_blocks: {with: ['PageBlockAttribute', 'PageBlockValue']}, | ||
}); | ||
templateData.values = HelperPage.arrayToObject(page.page_values, this.languageId); | ||
templateData.attributes = HelperPage.arrayToObject(page.page_attributes, this.languageId); | ||
templateData.items = HelperPage.itemsToObject(page.page_items, this.languageId); | ||
templateData.blocks = HelperPage.blocksToObject(page.blocks, this.languageId); | ||
templateData.blocks = HelperPage.blocksToObject(page.page_blocks, this.languageId); | ||
templateData.block_names= Object.keys(KohanaJS.config.cms.blocks) || []; | ||
templateData.language = this.language; | ||
templateData.placeholders = placeholders; | ||
templateData.autosave = this.request.session.autosave; | ||
@@ -207,17 +192,6 @@ const editTemplateFolder = page.page_type ?? 'default'; | ||
async syncMasterValues(){ | ||
const page = this.state.get('instance'); | ||
async syncMasterValues(page){ | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
if(this.language === KohanaJS.config.cms.defaultLanguage){ | ||
await HelperPage.defaultValue(page, page.page_type, database, this.languageId); | ||
return; | ||
} | ||
const masterLanguage = await ORM.readBy(Language, 'name', [KohanaJS.config.cms.defaultLanguage], {database, limit:1 }); | ||
await page.eagerLoad({ | ||
with: ['PageValue', 'PageItem', 'PageBlock'], | ||
page_items: {with: ['PageItemValue']}, | ||
page_blocks: {with: ['PageBlockValue']}, | ||
}) | ||
@@ -227,3 +201,3 @@ const masterPageObject = { | ||
items: HelperPage.itemsToObject(page.page_items, masterLanguage.id), | ||
blocks: HelperPage.blocksToObject(page.blocks, masterLanguage.id), | ||
blocks: HelperPage.blocksToObject(page.page_blocks, masterLanguage.id), | ||
} | ||
@@ -237,3 +211,3 @@ | ||
items: HelperPage.itemsToObject(page.page_items, this.languageId), | ||
blocks: HelperPage.blocksToObject(page.blocks, this.languageId), | ||
blocks: HelperPage.blocksToObject(page.page_blocks, this.languageId), | ||
} | ||
@@ -283,16 +257,191 @@ | ||
async pageEagerLoad(){ | ||
const page = this.state.get('instance'); | ||
await page.eagerLoad({ | ||
with:["PageAttribute", "PageValue", "PageItem", "PageBlock"], | ||
page_items: {with: ['PageItemValue']}, | ||
page_blocks: {with: ['PageBlockAttribute', 'PageBlockValue', 'PageBlockItem'], | ||
page_block_items: {with: ['PageBlockItemValue']} | ||
}, | ||
}); | ||
return page; | ||
} | ||
async action_create(){ | ||
await this.setEditTemplate(); | ||
this.setEditTemplate(await this.pageEagerLoad()); | ||
} | ||
async action_read() { | ||
await this.syncMasterValues(); | ||
await this.setEditTemplate(); | ||
const page = this.state.get('instance'); | ||
const placeholders = {}; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const masterLanguage = await ORM.readBy(Language, 'name', [KohanaJS.config.cms.defaultLanguage], {database, limit:1 }); | ||
const masterLanguageId = masterLanguage.id; | ||
await HelperPage.defaultMasterValue(page, database); | ||
if(this.language !== KohanaJS.config.cms.defaultLanguage){ | ||
placeholders.values = HelperPage.arrayToObject(page.page_values, masterLanguageId); | ||
placeholders.attributes = HelperPage.arrayToObject(page.page_attributes, masterLanguageId); | ||
placeholders.items = HelperPage.itemsToObject(page.page_items, masterLanguageId, "page_item_values"); | ||
placeholders.blocks = HelperPage.blocksToObject(page.page_blocks, masterLanguageId); | ||
await HelperPage.defaultLanguageValue(page, this.languageId, database); | ||
} | ||
this.setEditTemplate(page, placeholders); | ||
} | ||
async action_edit(){ | ||
await this.syncMasterValues(); | ||
await this.setEditTemplate(); | ||
await this.action_read(); | ||
} | ||
async action_delete(){ | ||
if(this.state.get(ControllerMixinORMDelete.DELETED)){ | ||
await this.unpublish(); | ||
//redirect to page type index | ||
const page = this.state.get(ControllerMixinORMDelete.INSTANCE); | ||
await this.redirect(`/admin/contents/list/${page.page_type}`); | ||
} | ||
} | ||
async action_add_item(){ | ||
const pageId = this.request.params['page_id']; | ||
const itemName= this.request.params['item_name']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const page = await ORM.factory(Page, pageId, {database}); | ||
if(!page) throw new Error(`Page ${pageId} not found`); | ||
const pageItems = await ORM.readWith(PageItem, [ | ||
['', 'page_id', SQL.EQUAL, page.id], | ||
[SQL.AND, 'name', SQL.EQUAL, itemName] | ||
], {database, asArray:true}); | ||
const masterItem = pageItems.filter(it => it.weight === 1)[0] || pageItems[0]; | ||
await masterItem.eagerLoad({with: ['PageItemValue']}); | ||
const template = masterItem.page_item_values; | ||
if(!template.length)throw new Error(`PageItem ${masterItem} is empty and cannot be copy`); | ||
const newPageItem = ORM.create(PageItem, {database}); | ||
newPageItem.page_id = page.id; | ||
newPageItem.name = masterItem.name; | ||
newPageItem.weight = pageItems.length; | ||
await newPageItem.write(); | ||
await Promise.all( | ||
template.map(async itemValue => { | ||
const newValue = ORM.create(PageItemValue, {database}); | ||
newValue.page_item_id = newPageItem.id; | ||
newValue.language_id = itemValue.language_id; | ||
newValue.name = itemValue.name; | ||
newValue.attribute_name = itemValue.attribute_name; | ||
newValue.value = ''; | ||
await newValue.write(); | ||
}) | ||
); | ||
await this.redirect(`/admin/pages/${page.id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
async action_delete_item(){ | ||
const item_id = this.request.params['item_id']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const item = await ORM.factory(PageItem, item_id, {database}); | ||
const page_id = item.page_id; | ||
await item.delete(); | ||
await this.redirect(`/admin/pages/${page_id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
async action_add_block_item(){ | ||
const blockId = this.request.params['block_id']; | ||
const itemName= this.request.params['item_name']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const block = await ORM.factory(PageBlock, blockId, {database}); | ||
if(!block) throw new Error(`Block ${blockId} not found`); | ||
const pageBlockItems = await ORM.readWith(PageBlockItem, [ | ||
['', 'page_block_id', SQL.EQUAL, block.id], | ||
[SQL.AND, 'name', SQL.EQUAL, itemName] | ||
], {database, asArray:true}); | ||
const masterItem = pageBlockItems.filter(it => it.weight === 1)[0] || pageBlockItems[0]; | ||
await masterItem.eagerLoad({with: ['PageBlockItemValue']}); | ||
const template = masterItem.page_block_item_values; | ||
if(!template.length)throw new Error(`PageItem ${masterItem} is empty and cannot be copy`); | ||
const newPageBlockItem = ORM.create(PageBlockItem, {database}); | ||
newPageBlockItem.page_block_id = block.id; | ||
newPageBlockItem.name = masterItem.name; | ||
newPageBlockItem.weight = pageBlockItems.length; | ||
await newPageBlockItem.write(); | ||
await Promise.all( | ||
template.map(async itemValue => { | ||
const newValue = ORM.create(PageBlockItemValue, {database}); | ||
newValue.page_block_item_id = newPageBlockItem.id; | ||
newValue.language_id = itemValue.language_id; | ||
newValue.name = itemValue.name; | ||
newValue.attribute_name = itemValue.attribute_name; | ||
newValue.value = ''; | ||
await newValue.write(); | ||
}) | ||
); | ||
await this.redirect(`/admin/pages/${block.page_id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
async action_delete_block_item(){ | ||
const item_id = this.request.params['item_id']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const item = await ORM.factory(PageBlockItem, item_id, {database}); | ||
const block_id = item.page_block_id; | ||
await item.delete(); | ||
const block = await ORM.factory(PageBlock, block_id, {database}); | ||
await this.redirect(`/admin/pages/${block.page_id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
async action_add_block(){ | ||
const page_id = this.request.params['page_id']; | ||
const blockName= this.request.params['block_name']; | ||
const blueprint = KohanaJS.config.cms.blocks[blockName]; | ||
if(!blueprint) throw new Error(`Block ${blockName} not defined in config`); | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const page = await ORM.factory(Page, page_id, {database}); | ||
if(!page) throw new Error(`Page ${page_id} not found`); | ||
const blocks = await ORM.readBy(PageBlock, 'page_id', [page.id], {database, limit: 99999}) | ||
const masterLanguage = await ORM.readBy(Language, 'name', [KohanaJS.config.cms.defaultLanguage], {database, limit:1 }); | ||
const blockId = ORM.defaultAdapter.defaultID(); | ||
const block = ORM.create(PageBlock, {database, insertID: blockId}); | ||
block.page_id = page.id; | ||
block.name = blockName; | ||
block.weight = blocks.length; | ||
await block.write(); | ||
await HelperPage.initBlock(blueprint, masterLanguage.id, PageBlockAttribute, PageBlockValue, PageBlockItem, PageBlockItemValue, 'page_block_id', blockId, 'page_block_item_id', database); | ||
await this.redirect(`/admin/pages/${page_id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
async action_delete_block(){ | ||
const block_id = this.request.params['block_id']; | ||
const database = this.state.get(ControllerMixinDatabase.DATABASES).get('draft'); | ||
const item = await ORM.factory(PageBlock, block_id, {database}); | ||
const page_id = item.page_id; | ||
await item.delete(); | ||
await this.redirect(`/admin/pages/${page_id}${this.language ? ("?language="+this.language) : ""}`); | ||
} | ||
} | ||
module.exports = ControllerAdminPage; |
@@ -0,1 +1,2 @@ | ||
const { SQL } = require("@kohanajs/constants") | ||
const { ORM, KohanaJS } = require("kohanajs"); | ||
@@ -6,5 +7,6 @@ const PageValue = ORM.require('PageValue'); | ||
const PageItemValue = ORM.require('PageItemValue'); | ||
const Language = ORM.require('Language'); | ||
class HelperPage{ | ||
static arrayToObject(values, languageId= 1){ | ||
static arrayToObject(values=[], languageId= 1){ | ||
const result = {}; | ||
@@ -25,20 +27,21 @@ values.forEach(it => { | ||
static itemsToObject(items, languageId=1){ | ||
static itemsToObject(items=[], languageId=1, children= "page_item_values"){ | ||
const result = {} | ||
items.forEach(x => { | ||
result[x.name] = result[x.name] || []; | ||
const obj = { _ : x }; | ||
items.forEach(item => { | ||
result[item.name] = result[item.name] || []; | ||
const obj = { _ : item, values : {} }; | ||
item.values = obj.values; | ||
x.page_item_values.forEach(y => { | ||
(item[children] || []).forEach(y => { | ||
if(y.language_id && y.language_id !== languageId)return; | ||
if(y.attribute_name){ | ||
obj[y.name] = obj[y.name] || {}; | ||
obj[y.name][y.attribute_name] = y; | ||
obj.values[y.name] = obj.values[y.name] || {}; | ||
obj.values[y.name][y.attribute_name] = y; | ||
return; | ||
} | ||
obj[y.name] = y; | ||
obj.values[y.name] = y; | ||
}) | ||
result[x.name].push(obj); | ||
result[item.name].push(obj); | ||
}); | ||
@@ -54,8 +57,17 @@ | ||
static blocksToObject(blocks){ | ||
//TODO, block | ||
return {}; | ||
static blocksToObject(blocks=[], languageId = 1){ | ||
const result = blocks.map(block =>({ | ||
_ : block, | ||
values: this.arrayToObject(block.page_block_values, languageId), | ||
attributes: this.arrayToObject(block.page_block_attributes, languageId), | ||
items: this.itemsToObject(block.page_block_items, languageId, "page_block_item_values"), | ||
})); | ||
//sort items by weight; | ||
result.sort((a, b) => (a._.weight || 0) - (b._.weight || 0)); | ||
return result; | ||
} | ||
static async create(mapName, model, name, attribute_name, instance, languageId, database){ | ||
static async create(model, name, attribute_name, parentId, languageId, fk, database){ | ||
const item = ORM.create(model, {database}); | ||
@@ -65,3 +77,3 @@ item.name = name; | ||
if(languageId)item.language_id = languageId; | ||
item.page_id = instance.id; | ||
item[fk] = parentId; | ||
item.value = ""; | ||
@@ -72,131 +84,165 @@ await item.write(); | ||
static async createEmptyValue(name, attribute_name, instance, languageId, database){ | ||
await this.create('pageValueMap', PageValue, name, attribute_name, instance, languageId, database); | ||
static async initBlock(blueprint, languageId, ModelAttribute, ModelValue, ModelItem, ModelItemValue, fk, parent_id, item_fk, database){ | ||
if(!blueprint) throw new Error(`Blueprint not defined in config`); | ||
//loop the blueprint | ||
const creators = []; | ||
blueprint.attributes.forEach(it => { | ||
creators.push(this.createField(it, {id: parent_id, attributes:{}}, [], 'attributes', ModelAttribute, fk, database, null)); | ||
}); | ||
blueprint.values.forEach(it => { | ||
creators.push(this.createField(it, {id: parent_id, values:{}}, [], 'values', ModelValue, fk, database, languageId)); | ||
}); | ||
//loop items | ||
Object.keys(blueprint.items).forEach(item_name => { | ||
const itemValues = blueprint.items[item_name]; | ||
const item = ORM.create(ModelItem, {database}); | ||
item.name = item_name; | ||
item[fk] = parent_id; | ||
item.values = {}; | ||
creators.push(item.write()); | ||
itemValues.forEach(it => { | ||
creators.push(this.createField(it, item, [], "values", ModelItemValue, item_fk, database, languageId)); | ||
}); | ||
}); | ||
await Promise.all(creators); | ||
} | ||
static async createEmptyAttribute(name, attribute_name, instance, database){ | ||
await this.create('pageAttributeMap', PageAttribute, name, attribute_name, instance, null, database); | ||
static async createField(blueprint, entity, entityChildren, fieldType, fieldModel, fk, database, languageId){ | ||
const creators = []; | ||
//attribute is array of (string | {name: string[] } ) | ||
//it is from config file | ||
if(typeof blueprint === "string") { | ||
if(entity[fieldType][blueprint])return; | ||
creators.push(this.create(fieldModel, blueprint, null, entity.id, languageId, fk, database).then(x => entityChildren.push(x))); | ||
}else{ | ||
const name = Object.keys(blueprint)[0]; | ||
blueprint[name].forEach(attr => { | ||
entity[fieldType][name] = entity[fieldType][name] || {}; | ||
if(entity[fieldType][name][attr])return; | ||
creators.push(this.create(fieldModel, name, attr, entity.id, languageId, fk, database).then(x => entityChildren.push(x))) | ||
}); | ||
} | ||
await Promise.all(creators) | ||
} | ||
static async createEmptyItemValue(item_name, value_name, subvalue, instance, languageId, database, index=0){ | ||
const item = ORM.create(PageItemValue, {database}); | ||
item.name = value_name; | ||
if(subvalue)item.attribute_name = subvalue; | ||
if(languageId)item.language_id = languageId; | ||
item.page_item_id = instance.items[item_name][index]._.id; | ||
item.value = ""; | ||
await item.write(); | ||
return item; | ||
static async updatePageObject(page, language_id){ | ||
await page.eagerLoad({ | ||
with:["PageAttribute", "PageValue", "PageItem", "PageBlock"], | ||
page_items: {with: ['PageItemValue']}, | ||
page_blocks: {with: ['PageBlockAttribute', 'PageBlockValue', 'PageBlockItem'], | ||
page_block_items: {with: ['PageBlockItemValue']} | ||
}, | ||
}); | ||
page.values = this.arrayToObject(page.page_values, language_id); | ||
page.attributes = this.arrayToObject(page.page_attributes, language_id); | ||
page.items = this.itemsToObject(page.page_items, language_id, "page_item_values"); | ||
} | ||
/** | ||
* | ||
* @param {Page} instance | ||
* @param {string} pageType | ||
* @param database | ||
* @param {number} languageId | ||
* @returns {Promise<void>} | ||
*/ | ||
static async defaultMasterValue(page, database){ | ||
const masterLanguage = await ORM.readBy(Language, 'name', [KohanaJS.config.cms.defaultLanguage], {database, limit:1 }); | ||
const masterLanguageId = masterLanguage.id; | ||
static async defaultValue(instance, pageType, database, languageId = 1){ | ||
const blueprint = KohanaJS.config.cms.blueprint || {}; | ||
const content = blueprint[pageType.toLowerCase()]; | ||
if(!content)throw new Error(`Creating undefined content by page type : ${pageType}`); | ||
const pageType = page.page_type; | ||
const blueprints = KohanaJS.config.cms.blueprint || {}; | ||
const blueprint = blueprints[pageType]; | ||
if(!blueprint)return; | ||
//prepare instance to check default value exists | ||
if(!instance.page_values || !instance.page_attributes || !instance.page_items ){ | ||
await instance.eagerLoad({ | ||
with: ['PageValue', 'PageAttribute', 'PageItem'], | ||
page_items: { | ||
with: ['PageItemValue'] | ||
} | ||
}); | ||
} | ||
await this.updatePageObject(page, masterLanguageId); | ||
if(!instance.values || !instance.attributes || !instance.items ){ | ||
instance.values = this.arrayToObject(instance.page_values, languageId); | ||
instance.attributes = this.arrayToObject(instance.page_attributes, languageId); | ||
instance.items = this.itemsToObject(instance.page_items, languageId); | ||
} | ||
//loop the blueprint | ||
const creators = []; | ||
await Promise.all( | ||
content.attributes.map(async it => { | ||
//it is from config file | ||
if(typeof it === "string") { | ||
if(instance.attributes[it])return; | ||
return await this.createEmptyAttribute(it, null, instance, database); | ||
} | ||
blueprint.attributes.forEach(it => { | ||
creators.push(this.createField(it, page, page.page_attributes, "attributes", PageAttribute, "page_id", database)); | ||
}); | ||
const name = Object.keys(it)[0]; | ||
const subvalues = it[name]; | ||
blueprint.values.forEach(it => { | ||
creators.push(this.createField(it, page, page.page_values, "values", PageValue, "page_id", database, masterLanguageId)); | ||
}); | ||
await Promise.all( | ||
subvalues.map(async attr => { | ||
if(instance.attributes[name] && instance.attributes[name][attr])return; | ||
await this.createEmptyAttribute(name, attr, instance, database) | ||
}) | ||
); | ||
}) | ||
) | ||
Object.keys(blueprint.items).forEach(item_name => { | ||
const blueprintItem = blueprint.items[item_name]; | ||
await Promise.all( | ||
content.values.map(async it => { | ||
if(typeof it === "string") { | ||
if(instance.values[it]) return; | ||
return await this.createEmptyValue(it, null, instance, languageId, database); | ||
} | ||
if(!page.items[item_name]){ | ||
//no item, create one | ||
const item = ORM.create(PageItem, {database}); | ||
item.name = item_name; | ||
item.page_id = page.id; | ||
item.page_item_values = []; | ||
const obj = { _ :item, values:{} }; | ||
item.values = obj.values; | ||
const name = Object.keys(it)[0]; | ||
const subvalues = it[name]; | ||
creators.push(item.write()); | ||
page.page_items.push(item); | ||
page.items[item_name] = [obj]; | ||
} | ||
await Promise.all( | ||
subvalues.map(async attr => { | ||
if(instance.values[name] && instance.values[name][attr])return; | ||
await this.createEmptyValue(name, attr, instance, languageId, database) | ||
}) | ||
); | ||
page.items[item_name].forEach(item =>{ | ||
//create item value by blueprint | ||
blueprintItem.forEach(it => { | ||
creators.push(this.createField(it, item._, item._.page_item_values, "values", PageItemValue, "page_item_id", database, masterLanguageId)); | ||
}); | ||
}) | ||
); | ||
}); | ||
await Promise.all(creators); | ||
} | ||
static getFieldMap(fields, prefix, language_id){ | ||
const result = new Map(); | ||
fields.forEach(it =>{ | ||
if(it.language_id === language_id){ | ||
result.set(`${prefix}::${it.name}::${it.attribute_name || ''}`, it); | ||
} | ||
}); | ||
return result; | ||
} | ||
static async fieldFactory(fields, prefix, master_language_id, language_id, mapCompare, database){ | ||
await Promise.all( | ||
Object.keys(content.items).map(async item_name => { | ||
if(!instance.items[item_name]){ | ||
instance.items[item_name] = []; | ||
const item = instance.items[item_name]; | ||
const firstItem = await ORM.readWith(PageItem, [['', 'page_id', SQL.EQUAL, instance.id], [SQL.AND, 'name', SQL.EQUAL, item_name], [SQL.AND, 'weight', SQL.EQUAL, 1]], {database}); | ||
fields.map(it => { | ||
if(it.language_id !== master_language_id)return; | ||
//check difference | ||
if(mapCompare.get(`${prefix}::${it.name}::${it.attribute_name || ""}`))return; | ||
//create languge fields | ||
if(!firstItem){ | ||
const firstItem = ORM.create(PageItem, {database}); | ||
firstItem.page_id = instance.id; | ||
firstItem.name = item_name; | ||
firstItem.weight = 1; | ||
await firstItem.write(); | ||
item[0] = {_: firstItem}; | ||
} | ||
} | ||
const field = ORM.create(it.constructor, {database}); | ||
Object.assign(field, it); | ||
field.id = null; | ||
field.language_id = language_id; | ||
field.value = ""; | ||
return field.write(); | ||
}) | ||
) | ||
} | ||
await Promise.all( | ||
content.items[item_name].map(async value => { | ||
if(typeof value === "string") { | ||
if(instance.items[item_name] && instance.items[item_name][0][value])return; | ||
return await this.createEmptyItemValue(item_name, value, null, instance, languageId, database); | ||
} | ||
static async defaultLanguageValue(page, language_id, database){ | ||
const masterLanguage = await ORM.readBy(Language, 'name', [KohanaJS.config.cms.defaultLanguage], {database, limit:1 }); | ||
const masterLanguageId = masterLanguage.id; | ||
//queue all fields | ||
//map languge fields | ||
const valueMap = this.getFieldMap(page.page_values, '', language_id); | ||
const itemValueMap = new Map(page.page_items.map(item => [...this.getFieldMap(item.page_item_values, item.id, language_id)]).flat()); | ||
const blockValueMap = new Map(page.page_blocks.map(block => [...this.getFieldMap(block.page_block_values, block.id, language_id)]).flat()); | ||
const blockItemValueMap = new Map(page.page_blocks.map(block => block.page_block_items.map(item => [...this.getFieldMap(item.page_block_item_values, item.id, language_id)]).flat(2))); | ||
const valueName = Object.keys(value)[0]; | ||
await Promise.all( | ||
value[valueName].map(async subvalue => { | ||
//guard item value with attribute exist | ||
if( | ||
instance.items[item_name][0] && | ||
instance.items[item_name][0][valueName] && | ||
instance.items[item_name][0][valueName][subvalue] | ||
)return; | ||
//loop master fields to find undefined language fields | ||
await Promise.all([ | ||
this.fieldFactory(page.page_values, '', masterLanguageId, language_id, valueMap, database), | ||
...page.page_items.map(item => this.fieldFactory(item.page_item_values, item.id, masterLanguageId, language_id, itemValueMap, database)), | ||
...page.page_blocks.map(block => this.fieldFactory(block.page_block_values, block.id, masterLanguageId, language_id, blockValueMap, database)), | ||
...page.page_blocks.map(async block => await Promise.all(block.page_block_items.map(item => this.fieldFactory(item.page_block_item_values, item.id, masterLanguageId, language_id, blockItemValueMap, database)))), | ||
]); | ||
await this.createEmptyItemValue(item_name, valueName, subvalue, instance, languageId, database) | ||
}) | ||
); | ||
}) | ||
) | ||
}) | ||
); | ||
await this.updatePageObject(page, language_id); | ||
} | ||
@@ -203,0 +249,0 @@ } |
@@ -16,3 +16,4 @@ const {ORM} = require('kohanajs'); | ||
["language_id", "PageItemValue"], | ||
["language_id", "PageBlockValue"] | ||
["language_id", "PageBlockValue"], | ||
["language_id", "PageBlockItemValue"] | ||
]; | ||
@@ -19,0 +20,0 @@ } |
@@ -5,2 +5,3 @@ const {ORM} = require('kohanajs'); | ||
page_id = null; | ||
name = null; | ||
weight = 0; | ||
@@ -12,2 +13,3 @@ | ||
static fields = new Map([ | ||
["name", "String"], | ||
["weight", "Int"] | ||
@@ -20,3 +22,4 @@ ]); | ||
["page_block_id", "PageBlockAttribute"], | ||
["page_block_id", "PageBlockValue"] | ||
["page_block_id", "PageBlockValue"], | ||
["page_block_id", "PageBlockItem"] | ||
]; | ||
@@ -23,0 +26,0 @@ } |
@@ -16,2 +16,25 @@ const { KohanaJS } = require('kohanajs'); | ||
}, | ||
blocks: { | ||
logos : { | ||
attributes:[], | ||
values: ['label'], | ||
items:{ | ||
pictures: ["url"] | ||
} | ||
}, | ||
timelines:{ | ||
attributes:["start-year", "end-year"], | ||
values:["subject"], | ||
items: { | ||
events: ["subject", "body"] | ||
} | ||
}, | ||
paragraphs:{ | ||
attributes: [], | ||
values: ["subject", "body", "picture", "caption", "description"], | ||
items: {} | ||
} | ||
} | ||
}; |
10
init.js
@@ -9,2 +9,10 @@ const {KohanaJS} = require('kohanajs') | ||
RouteList.add('/admin/pages/add-block/:page_id/:block_name', 'controller/admin/Page', 'add_block'); | ||
RouteList.add('/admin/pages/delete-block/:block_id', 'controller/admin/Page', 'delete_block'); | ||
RouteList.add('/admin/pages/add-block-item/:block_id/:item_name', 'controller/admin/Page', 'add_block_item'); | ||
RouteList.add('/admin/pages/delete-block-item/:item_id', 'controller/admin/Page', 'delete_block_item'); | ||
RouteList.add('/admin/pages/add-item/:page_id/:item_name', 'controller/admin/Page', 'add_item'); | ||
RouteList.add('/admin/pages/delete-item/:item_id', 'controller/admin/Page', 'delete_item'); | ||
RouteList.add('/admin/pages/un-publish/:id', 'controller/admin/Page', 'unpublish'); | ||
@@ -15,4 +23,2 @@ RouteCRUD.add('pages', 'controller/admin/Page'); | ||
RouteList.add('/admin/contents/create/:page_type', 'controller/admin/Content', 'create_by_type'); | ||
RouteList.add('/admin/contents/page-add-item/:page_id/:item_name', 'controller/admin/Content', 'page_add_item'); | ||
RouteList.add('/admin/contents/page-delete-item/:item_id', 'controller/admin/Content', 'page_delete_item'); | ||
{ | ||
"name": "@kohanajs/mod-cms", | ||
"version": "4.0.0", | ||
"version": "4.2.0", | ||
"description": "The CMS module for KohanaJS", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42066
25
955