mirror of
https://github.com/documize/community.git
synced 2025-07-19 13:19:43 +02:00
re-worked to use new BLOCK table
This commit is contained in:
parent
b7fa3b9006
commit
bbc2237ef7
25 changed files with 1080 additions and 903 deletions
|
@ -25,8 +25,8 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, {
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.get('sectionService').getSpaceSectionTemplates(this.get('folder.id')).then((t) => {
|
this.get('sectionService').getSpaceBlocks(this.get('folder.id')).then((b) => {
|
||||||
this.set('templates', t);
|
this.set('blocks', b);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -101,9 +101,9 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, {
|
||||||
this.attrs.onAddSection(section);
|
this.attrs.onAddSection(section);
|
||||||
},
|
},
|
||||||
|
|
||||||
onInsertTemplate(template) {
|
onInsertBlock(block) {
|
||||||
this.send('showToc');
|
this.send('showToc');
|
||||||
this.attrs.onInsertTemplate(template);
|
this.attrs.onInsertBlock(block);
|
||||||
},
|
},
|
||||||
|
|
||||||
scrollTop() {
|
scrollTop() {
|
||||||
|
|
|
@ -70,14 +70,8 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
onSaveAsPage(id, title) {
|
onAddBlock(block) {
|
||||||
let params = {
|
this.attrs.onAddBlock(block);
|
||||||
documentId: this.get('document.id'),
|
|
||||||
pageId: id,
|
|
||||||
title: title,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.attrs.onSaveAsPage(params);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeletePage(id, deleteChildren) {
|
onDeletePage(id, deleteChildren) {
|
||||||
|
|
|
@ -13,14 +13,16 @@ import Ember from 'ember';
|
||||||
import TooltipMixin from '../../mixins/tooltip';
|
import TooltipMixin from '../../mixins/tooltip';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
computed
|
computed,
|
||||||
|
inject: { service }
|
||||||
} = Ember;
|
} = Ember;
|
||||||
|
|
||||||
export default Ember.Component.extend(TooltipMixin, {
|
export default Ember.Component.extend(TooltipMixin, {
|
||||||
|
documentService: service('document'),
|
||||||
deleteChildren: false,
|
deleteChildren: false,
|
||||||
menuOpen: false,
|
menuOpen: false,
|
||||||
saveAsTitle: "",
|
blockTitle: "",
|
||||||
|
blockExcerpt: "",
|
||||||
|
|
||||||
checkId: computed('page', function () {
|
checkId: computed('page', function () {
|
||||||
let id = this.get('page.id');
|
let id = this.get('page.id');
|
||||||
|
@ -42,9 +44,13 @@ export default Ember.Component.extend(TooltipMixin, {
|
||||||
let id = this.get('page.id');
|
let id = this.get('page.id');
|
||||||
return `save-as-dialog-${id}`;
|
return `save-as-dialog-${id}`;
|
||||||
}),
|
}),
|
||||||
saveAsTitleId: computed('page', function () {
|
blockTitleId: computed('page', function () {
|
||||||
let id = this.get('page.id');
|
let id = this.get('page.id');
|
||||||
return `save-as-title-${id}`;
|
return `block-title-${id}`;
|
||||||
|
}),
|
||||||
|
blockExcerptId: computed('page', function () {
|
||||||
|
let id = this.get('page.id');
|
||||||
|
return `block-excerpt-${id}`;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
didRender() {
|
didRender() {
|
||||||
|
@ -55,7 +61,8 @@ export default Ember.Component.extend(TooltipMixin, {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#" + this.get('saveAsTitleId')).removeClass('error');
|
$("#" + this.get('blockTitleId')).removeClass('error');
|
||||||
|
$("#" + this.get('blockExcerptId')).removeClass('error');
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
|
@ -79,20 +86,44 @@ export default Ember.Component.extend(TooltipMixin, {
|
||||||
this.attrs.onDeletePage(id, this.get('deleteChildren'));
|
this.attrs.onDeletePage(id, this.get('deleteChildren'));
|
||||||
},
|
},
|
||||||
|
|
||||||
saveAsPage(id) {
|
onAddBlock(page) {
|
||||||
let titleElem = '#' + this.get('saveAsTitleId');
|
let titleElem = '#' + this.get('blockTitleId');
|
||||||
let saveAsTitle = this.get('saveAsTitle');
|
let blockTitle = this.get('blockTitle');
|
||||||
if (is.empty(saveAsTitle)) {
|
if (is.empty(blockTitle)) {
|
||||||
$(titleElem).addClass('error');
|
$(titleElem).addClass('error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.attrs.onSaveAsPage(id, saveAsTitle);
|
let excerptElem = '#' + this.get('blockExcerptId');
|
||||||
this.set('menuOpen', false);
|
let blockExcerpt = this.get('blockExcerpt');
|
||||||
this.set('saveAsTitle', '');
|
blockExcerpt = blockExcerpt.replace(/\n/g, "");
|
||||||
$(titleElem).removeClass('error');
|
if (is.empty(blockExcerpt)) {
|
||||||
|
$(excerptElem).addClass('error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
this.get('documentService').getPageMeta(this.get('document.id'), page.get('id')).then((pm) => {
|
||||||
|
let block = {
|
||||||
|
folderId: this.get('folder.id'),
|
||||||
|
contentType: page.get('contentType'),
|
||||||
|
pageType: page.get('pageType'),
|
||||||
|
title: blockTitle,
|
||||||
|
body: page.get('body'),
|
||||||
|
excerpt: blockExcerpt,
|
||||||
|
rawBody: pm.get('rawBody'),
|
||||||
|
config: pm.get('config'),
|
||||||
|
externalSource: pm.get('externalSource')
|
||||||
|
};
|
||||||
|
|
||||||
|
this.attrs.onAddBlock(block);
|
||||||
|
this.set('menuOpen', false);
|
||||||
|
this.set('blockTitle', '');
|
||||||
|
this.set('blockExcerpt', '');
|
||||||
|
$(titleElem).removeClass('error');
|
||||||
|
$(excerptElem).removeClass('error');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,8 +17,7 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
hasTemplates: false,
|
hasTemplates: false,
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
console.log(this.get('templates.length'));
|
this.set('hasBlocks', this.get('blocks.length') > 0);
|
||||||
this.set('hasTemplates', this.get('templates.length') > 0);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
didRender() {
|
didRender() {
|
||||||
|
@ -43,8 +42,8 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
this.attrs.onAddSection(section);
|
this.attrs.onAddSection(section);
|
||||||
},
|
},
|
||||||
|
|
||||||
insertTemplate(template) {
|
onInsertBlock(block) {
|
||||||
this.attrs.onInsertTemplate(template);
|
this.attrs.onInsertBlock(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, {
|
||||||
};
|
};
|
||||||
|
|
||||||
saved.forEach(function(t) {
|
saved.forEach(function(t) {
|
||||||
t.img = "template-saved";
|
Ember.set(t, 'img', 'template-saved');
|
||||||
});
|
});
|
||||||
|
|
||||||
saved.unshiftObject(emptyTemplate);
|
saved.unshiftObject(emptyTemplate);
|
||||||
|
|
|
@ -13,14 +13,18 @@ import Model from 'ember-data/model';
|
||||||
import attr from 'ember-data/attr';
|
import attr from 'ember-data/attr';
|
||||||
|
|
||||||
export default Model.extend({
|
export default Model.extend({
|
||||||
documentId: attr('string'),
|
|
||||||
orgId: attr('string'),
|
orgId: attr('string'),
|
||||||
|
folderId: attr('string'),
|
||||||
|
userId: attr('string'),
|
||||||
contentType: attr('string'),
|
contentType: attr('string'),
|
||||||
pageType: attr('string'),
|
pageType: attr('string'),
|
||||||
preset: attr('boolean', { defaultValue: false }),
|
|
||||||
presetId: attr('string'),
|
|
||||||
title: attr('string'),
|
title: attr('string'),
|
||||||
body: attr('string'),
|
body: attr('string'),
|
||||||
|
excerpt: attr('string'),
|
||||||
|
used: attr('number', { defaultValue: 0 }),
|
||||||
|
rawBody: attr(),
|
||||||
|
config: attr(),
|
||||||
|
externalSource: attr('boolean', { defaultValue: false }),
|
||||||
firstname: attr('string'),
|
firstname: attr('string'),
|
||||||
lastname: attr('string'),
|
lastname: attr('string'),
|
||||||
created: attr(),
|
created: attr(),
|
|
@ -22,8 +22,7 @@ export default Model.extend({
|
||||||
level: attr('number', { defaultValue: 1 }),
|
level: attr('number', { defaultValue: 1 }),
|
||||||
sequence: attr('number', { defaultValue: 0 }),
|
sequence: attr('number', { defaultValue: 0 }),
|
||||||
revisions: attr('number', { defaultValue: 0 }),
|
revisions: attr('number', { defaultValue: 0 }),
|
||||||
preset: attr('boolean', { defaultValue: false }),
|
blockId: attr('string'),
|
||||||
presetId: attr('string'),
|
|
||||||
title: attr('string'),
|
title: attr('string'),
|
||||||
body: attr('string'),
|
body: attr('string'),
|
||||||
rawBody: attr('string'),
|
rawBody: attr('string'),
|
||||||
|
|
|
@ -142,24 +142,25 @@ export default Ember.Controller.extend(NotifierMixin, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onInsertTemplate(template) {
|
onInsertBlock(block) {
|
||||||
this.audit.record("added-section-template-" + template.get('contentType'));
|
this.audit.record("added-content-block-" + block.get('contentType'));
|
||||||
|
|
||||||
let page = {
|
let page = {
|
||||||
documentId: this.get('model.document.id'),
|
documentId: this.get('model.document.id'),
|
||||||
title: `${template.get('title')}`,
|
title: `${block.get('title')}`,
|
||||||
level: 1,
|
level: 1,
|
||||||
sequence: 0,
|
sequence: 0,
|
||||||
body: template.get('body'),
|
body: block.get('body'),
|
||||||
contentType: template.get('contentType'),
|
contentType: block.get('contentType'),
|
||||||
pageType: template.get('pageType'),
|
pageType: block.get('pageType'),
|
||||||
presetId: template.get('id')
|
blockId: block.get('id')
|
||||||
};
|
};
|
||||||
|
|
||||||
let meta = {
|
let meta = {
|
||||||
documentId: this.get('model.document.id'),
|
documentId: this.get('model.document.id'),
|
||||||
rawBody: "",
|
rawBody: block.get('rawBody'),
|
||||||
config: ""
|
config: block.get('config'),
|
||||||
|
externalSource: block.get('externalSource')
|
||||||
};
|
};
|
||||||
|
|
||||||
let model = {
|
let model = {
|
||||||
|
|
|
@ -86,8 +86,8 @@ export default Ember.Controller.extend(NotifierMixin, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onSaveAsPage(params) {
|
onAddBlock(block) {
|
||||||
this.get('sectionService').saveSectionTemplate(params).then(() => {
|
this.get('sectionService').addBlock(block).then(() => {
|
||||||
this.showNotification("Published");
|
this.showNotification("Published");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
{{document/document-view document=model.document links=model.links allPages=model.allPages tabs=model.tabs pages=model.pages folder=model.folder folders=model.folders isEditor=model.isEditor
|
{{document/document-view document=model.document links=model.links allPages=model.allPages tabs=model.tabs pages=model.pages folder=model.folder folders=model.folders isEditor=model.isEditor
|
||||||
gotoPage=(action 'gotoPage') onSaveAsPage=(action 'onSaveAsPage') onDeletePage=(action 'onPageDeleted')}}
|
gotoPage=(action 'gotoPage') onAddBlock=(action 'onAddBlock') onDeletePage=(action 'onPageDeleted')}}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{{#layout/zone-sidebar}}
|
{{#layout/zone-sidebar}}
|
||||||
{{document/document-sidebar document=model.document folder=model.folder pages=model.pages page=model.page isEditor=model.isEditor sections=model.sections
|
{{document/document-sidebar document=model.document folder=model.folder pages=model.pages page=model.page isEditor=model.isEditor sections=model.sections
|
||||||
onAddSection=(action 'onAddSection') onInsertTemplate=(action 'onInsertTemplate') changePageSequence=(action 'onPageSequenceChange') changePageLevel=(action 'onPageLevelChange') gotoPage=(action 'gotoPage')}}
|
onAddSection=(action 'onAddSection') onInsertBlock=(action 'onInsertBlock') changePageSequence=(action 'onPageSequenceChange') changePageLevel=(action 'onPageLevelChange') gotoPage=(action 'gotoPage')}}
|
||||||
{{/layout/zone-sidebar}}
|
{{/layout/zone-sidebar}}
|
||||||
|
|
||||||
{{#layout/zone-content}}
|
{{#layout/zone-content}}
|
||||||
|
|
|
@ -70,13 +70,13 @@ export default BaseService.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/******************************
|
/**************************************************
|
||||||
* Reusable section blocks
|
* Reusable Content Blocks
|
||||||
******************************/
|
**************************************************/
|
||||||
|
|
||||||
// Saves section as template
|
// Save new reusable content block.
|
||||||
saveSectionTemplate(payload) {
|
addBlock(payload) {
|
||||||
let url = `sections/templates`;
|
let url = `sections/blocks`;
|
||||||
|
|
||||||
return this.get('ajax').post(url, {
|
return this.get('ajax').post(url, {
|
||||||
data: JSON.stringify(payload),
|
data: JSON.stringify(payload),
|
||||||
|
@ -84,15 +84,15 @@ export default BaseService.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Returns all available sections.
|
// Returns all available reusable content block for section.
|
||||||
getSpaceSectionTemplates(folderId) {
|
getSpaceBlocks(folderId) {
|
||||||
return this.get('ajax').request(`sections/templates/${folderId}`, {
|
return this.get('ajax').request(`sections/blocks/${folderId}`, {
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
let data = [];
|
let data = [];
|
||||||
|
|
||||||
data = response.map((obj) => {
|
data = response.map((obj) => {
|
||||||
let data = this.get('store').normalize('pageTemplate', obj);
|
let data = this.get('store').normalize('block', obj);
|
||||||
return this.get('store').push(data);
|
return this.get('store').push(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
gotoPage=(action 'gotoPage')}}
|
gotoPage=(action 'gotoPage')}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if showSections}}
|
{{#if showSections}}
|
||||||
{{document/page-wizard display='section' document=document folder=folder sections=sections templates=templates
|
{{document/page-wizard display='section' document=document folder=folder sections=sections blocks=blocks
|
||||||
onCancel=(action 'onCancel') onAddSection=(action 'onAddSection') onInsertTemplate=(action 'onInsertTemplate')}}
|
onCancel=(action 'onCancel') onAddSection=(action 'onAddSection') onInsertBlock=(action 'onInsertBlock')}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
{{#each pages key="id" as |page index|}}
|
{{#each pages key="id" as |page index|}}
|
||||||
<div class="wysiwyg">
|
<div class="wysiwyg">
|
||||||
<div id="page-{{ page.id }}" class="is-a-page" data-id="{{ page.id }}" data-type="{{ page.contentType }}">
|
<div id="page-{{ page.id }}" class="is-a-page" data-id="{{ page.id }}" data-type="{{ page.contentType }}">
|
||||||
{{document/page-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor onSaveAsPage=(action 'onSaveAsPage') onDeletePage=(action 'onDeletePage')}}
|
{{document/page-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor onAddBlock=(action 'onAddBlock') onDeletePage=(action 'onDeletePage')}}
|
||||||
{{section/base-renderer page=page}}
|
{{section/base-renderer page=page}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<label for="{{checkId}}"> Delete child pages</label>
|
<label for="{{checkId}}"> Delete child pages</label>
|
||||||
</p>
|
</p>
|
||||||
{{/dropdown-dialog}}
|
{{/dropdown-dialog}}
|
||||||
{{#dropdown-dialog id=saveAsDialogId target=saveAsTarget position="top right" button="Publish" color="flat-green" focusOn=saveAsTitleId onAction=(action 'saveAsPage' page.id)}}
|
{{#dropdown-dialog id=saveAsDialogId target=saveAsTarget position="top right" button="Publish" color="flat-green" focusOn=blockTitleId onAction=(action 'onAddBlock' page)}}
|
||||||
<div class="form-header">
|
<div class="form-header">
|
||||||
<div class="tip">
|
<div class="tip">
|
||||||
<span class="bold">{{folder.name}}:</span> Content Block
|
<span class="bold">{{folder.name}}:</span> Content Block
|
||||||
|
@ -38,8 +38,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Name</label>
|
<label>Name</label>
|
||||||
<div class="tip">Short description to help others understand<br/>this reusable content block</div>
|
<div class="tip">Short title for reusable content block</div>
|
||||||
{{textarea rows="3" value=saveAsTitle id=saveAsTitleId}}
|
{{input type="text" value=blockTitle id=blockTitleId}}
|
||||||
|
</div>
|
||||||
|
<div class="input-control">
|
||||||
|
<label>Name</label>
|
||||||
|
<div class="tip">Short description to help others understand<br/>the reusable content block</div>
|
||||||
|
{{textarea rows="3" value=blockExcerpt id=blockExcerptId}}
|
||||||
</div>
|
</div>
|
||||||
{{/dropdown-dialog}}
|
{{/dropdown-dialog}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -19,25 +19,29 @@
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
{{#if hasTemplates}}
|
{{#if hasBlocks}}
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="template-caption">Published content blocks</div>
|
<div class="template-caption">Reusable Content</div>
|
||||||
<ul class="list">
|
<ul class="list">
|
||||||
{{#each templates as |template|}}
|
{{#each blocks as |block|}}
|
||||||
<li class="item" {{action 'insertTemplate' template}}>
|
<li class="item" {{action 'onInsertBlock' block}}>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img class="img" src="/assets/img/section-saved.png" srcset="/assets/img/section-saved@2x.png" />
|
<img class="img" src="/assets/img/section-saved.png" srcset="/assets/img/section-saved@2x.png" />
|
||||||
</div>
|
</div>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<div class='title'>
|
<div class='title'>
|
||||||
{{template.title}}
|
{{block.title}}
|
||||||
</div>
|
</div>
|
||||||
<div class='desc'>{{template.firstname}} {{template.lastname}} · {{time-ago template.created}}</div>
|
<div class='desc'>{{block.excerpt}}</div>
|
||||||
|
<div class='desc'>By {{block.firstname}} {{block.lastname}}, {{time-ago block.created}} (used: {{ block.used }})</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix" />
|
<div class="clearfix" />
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
{{else}}
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="template-caption">No reusable content</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -78,23 +78,13 @@ func AddDocumentPage(w http.ResponseWriter, r *http.Request) {
|
||||||
pageID := util.UniqueID()
|
pageID := util.UniqueID()
|
||||||
model.Page.RefID = pageID
|
model.Page.RefID = pageID
|
||||||
model.Meta.PageID = pageID
|
model.Meta.PageID = pageID
|
||||||
|
model.Meta.OrgID = p.Context.OrgID // required for Render call below
|
||||||
|
model.Meta.UserID = p.Context.UserID // required for Render call below
|
||||||
model.Page.SetDefaults()
|
model.Page.SetDefaults()
|
||||||
model.Meta.SetDefaults()
|
model.Meta.SetDefaults()
|
||||||
// page.Title = template.HTMLEscapeString(page.Title)
|
// page.Title = template.HTMLEscapeString(page.Title)
|
||||||
|
|
||||||
// laod previous meta if page is being created from published template
|
|
||||||
if model.Page.PresetID != "" {
|
|
||||||
em, err2 := p.GetPageMeta(model.Page.PresetID)
|
|
||||||
if err2 != nil {
|
|
||||||
writeGeneralSQLError(w, method, err2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
model.Meta = em
|
|
||||||
model.Meta.PageID = pageID
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := request.Db.Beginx()
|
tx, err := request.Db.Beginx()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeTransactionError(w, method, err)
|
writeTransactionError(w, method, err)
|
||||||
return
|
return
|
||||||
|
@ -102,8 +92,7 @@ func AddDocumentPage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
p.Context.Transaction = tx
|
p.Context.Transaction = tx
|
||||||
|
|
||||||
output, ok := provider.Render(model.Page.ContentType,
|
output, ok := provider.Render(model.Page.ContentType, provider.NewContext(model.Meta.OrgID, model.Meta.UserID), model.Meta.Config, model.Meta.RawBody)
|
||||||
provider.NewContext(model.Meta.OrgID, model.Meta.UserID), model.Meta.Config, model.Meta.RawBody)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.ErrorString("provider.Render could not find: " + model.Page.ContentType)
|
log.ErrorString("provider.Render could not find: " + model.Page.ContentType)
|
||||||
}
|
}
|
||||||
|
@ -111,13 +100,16 @@ func AddDocumentPage(w http.ResponseWriter, r *http.Request) {
|
||||||
model.Page.Body = output
|
model.Page.Body = output
|
||||||
|
|
||||||
err = p.AddPage(*model)
|
err = p.AddPage(*model)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.IfErr(tx.Rollback())
|
log.IfErr(tx.Rollback())
|
||||||
writeGeneralSQLError(w, method, err)
|
writeGeneralSQLError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(model.Page.BlockID) > 0 {
|
||||||
|
p.IncrementBlockUsage(model.Page.BlockID)
|
||||||
|
}
|
||||||
|
|
||||||
log.IfErr(tx.Commit())
|
log.IfErr(tx.Commit())
|
||||||
|
|
||||||
newPage, _ := p.GetPage(pageID)
|
newPage, _ := p.GetPage(pageID)
|
||||||
|
@ -324,6 +316,17 @@ func DeleteDocumentPage(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page, err := p.GetPage(pageID)
|
||||||
|
if err != nil {
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(page.BlockID) > 0 {
|
||||||
|
p.DecrementBlockUsage(page.BlockID)
|
||||||
|
}
|
||||||
|
|
||||||
log.IfErr(tx.Commit())
|
log.IfErr(tx.Commit())
|
||||||
|
|
||||||
writeSuccessEmptyJSON(w)
|
writeSuccessEmptyJSON(w)
|
||||||
|
@ -374,12 +377,22 @@ func DeleteDocumentPages(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
for _, page := range *model {
|
for _, page := range *model {
|
||||||
_, err = p.DeletePage(documentID, page.PageID)
|
_, err = p.DeletePage(documentID, page.PageID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.IfErr(tx.Rollback())
|
log.IfErr(tx.Rollback())
|
||||||
writeGeneralSQLError(w, method, err)
|
writeGeneralSQLError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pageData, err := p.GetPage(page.PageID)
|
||||||
|
if err != nil {
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pageData.BlockID) > 0 {
|
||||||
|
p.DecrementBlockUsage(pageData.BlockID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.IfErr(tx.Commit())
|
log.IfErr(tx.Commit())
|
||||||
|
@ -884,145 +897,3 @@ func RollbackDocumentPage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
writeSuccessBytes(w, payload)
|
writeSuccessBytes(w, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************
|
|
||||||
* Page Templates
|
|
||||||
********************/
|
|
||||||
|
|
||||||
type sectionTemplate struct {
|
|
||||||
DocumentID string `json:"documentId"`
|
|
||||||
PageID string `json:"pageId"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SavePageAsTemplate inserts new section into document.
|
|
||||||
func SavePageAsTemplate(w http.ResponseWriter, r *http.Request) {
|
|
||||||
method := "SavePageAsTemplate"
|
|
||||||
p := request.GetPersister(r)
|
|
||||||
|
|
||||||
defer utility.Close(r.Body)
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
writeBadRequestError(w, method, "Bad payload")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := new(sectionTemplate)
|
|
||||||
err = json.Unmarshal(body, &payload)
|
|
||||||
if err != nil {
|
|
||||||
writePayloadError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data checks
|
|
||||||
if len(payload.DocumentID) == 0 {
|
|
||||||
writeMissingDataError(w, method, "documentID")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(payload.PageID) == 0 {
|
|
||||||
writeMissingDataError(w, method, "pageID")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(payload.Title) == 0 {
|
|
||||||
writeMissingDataError(w, method, "title")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !p.CanChangeDocument(payload.DocumentID) {
|
|
||||||
writeForbiddenError(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if strings.HasPrefix(newTitle, "\"") {
|
|
||||||
// newTitle = newTitle[1:]
|
|
||||||
// }
|
|
||||||
// if strings.HasSuffix(newTitle, "\"") {
|
|
||||||
// newTitle = newTitle[:len(newTitle)-1]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// get previous page
|
|
||||||
prevPage, err := p.GetPage(payload.PageID)
|
|
||||||
if err != nil {
|
|
||||||
writeServerError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
prevMeta, err := p.GetPageMeta(payload.PageID)
|
|
||||||
if err != nil {
|
|
||||||
writeServerError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// safety check
|
|
||||||
if prevPage.DocumentID != payload.DocumentID || prevMeta.DocumentID != payload.DocumentID {
|
|
||||||
writeUnauthorizedError(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
newID := util.UniqueID()
|
|
||||||
prevPage.RefID = newID
|
|
||||||
prevPage.Preset = true
|
|
||||||
prevPage.Title = payload.Title
|
|
||||||
prevMeta.PageID = newID
|
|
||||||
|
|
||||||
tx, err := request.Db.Beginx()
|
|
||||||
if err != nil {
|
|
||||||
writeTransactionError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Context.Transaction = tx
|
|
||||||
|
|
||||||
model := new(models.PageModel)
|
|
||||||
model.Page = prevPage
|
|
||||||
model.Meta = prevMeta
|
|
||||||
|
|
||||||
err = p.AddPage(*model)
|
|
||||||
if err != nil {
|
|
||||||
log.IfErr(tx.Rollback())
|
|
||||||
writeGeneralSQLError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.IfErr(tx.Commit())
|
|
||||||
|
|
||||||
writeSuccessEmptyJSON(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSpaceSectionTemplates gets published section templates
|
|
||||||
func GetSpaceSectionTemplates(w http.ResponseWriter, r *http.Request) {
|
|
||||||
method := "GetSpaceSectionTemplates"
|
|
||||||
p := request.GetPersister(r)
|
|
||||||
|
|
||||||
params := mux.Vars(r)
|
|
||||||
folderID := params["folderID"]
|
|
||||||
|
|
||||||
if len(folderID) == 0 {
|
|
||||||
writeMissingDataError(w, method, "folderID")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pages []entity.PageTemplate
|
|
||||||
var err error
|
|
||||||
|
|
||||||
pages, err = p.GetSpaceSectionTemplates(folderID)
|
|
||||||
|
|
||||||
if len(pages) == 0 {
|
|
||||||
pages = []entity.PageTemplate{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
writeGeneralSQLError(w, method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
json, err := json.Marshal(pages)
|
|
||||||
if err != nil {
|
|
||||||
writeJSONMarshalError(w, method, "page", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
writeSuccessBytes(w, json)
|
|
||||||
}
|
|
||||||
|
|
|
@ -216,8 +216,8 @@ func init() {
|
||||||
log.IfErr(Add(RoutePrefixPrivate, "sections", []string{"GET", "OPTIONS"}, nil, GetSections))
|
log.IfErr(Add(RoutePrefixPrivate, "sections", []string{"GET", "OPTIONS"}, nil, GetSections))
|
||||||
log.IfErr(Add(RoutePrefixPrivate, "sections", []string{"POST", "OPTIONS"}, nil, RunSectionCommand))
|
log.IfErr(Add(RoutePrefixPrivate, "sections", []string{"POST", "OPTIONS"}, nil, RunSectionCommand))
|
||||||
log.IfErr(Add(RoutePrefixPrivate, "sections/refresh", []string{"GET", "OPTIONS"}, nil, RefreshSections))
|
log.IfErr(Add(RoutePrefixPrivate, "sections/refresh", []string{"GET", "OPTIONS"}, nil, RefreshSections))
|
||||||
log.IfErr(Add(RoutePrefixPrivate, "sections/templates/{folderID}", []string{"GET", "OPTIONS"}, nil, GetSpaceSectionTemplates))
|
log.IfErr(Add(RoutePrefixPrivate, "sections/blocks/{folderID}", []string{"GET", "OPTIONS"}, nil, GetBlocksForSpace))
|
||||||
log.IfErr(Add(RoutePrefixPrivate, "sections/templates", []string{"POST", "OPTIONS"}, nil, SavePageAsTemplate))
|
log.IfErr(Add(RoutePrefixPrivate, "sections/blocks", []string{"POST", "OPTIONS"}, nil, AddBlock))
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
log.IfErr(Add(RoutePrefixPrivate, "links/{folderID}/{documentID}/{pageID}", []string{"GET", "OPTIONS"}, nil, GetLinkCandidates))
|
log.IfErr(Add(RoutePrefixPrivate, "links/{folderID}/{documentID}/{pageID}", []string{"GET", "OPTIONS"}, nil, GetLinkCandidates))
|
||||||
|
|
|
@ -13,6 +13,7 @@ package endpoint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/documize/community/core/api/entity"
|
"github.com/documize/community/core/api/entity"
|
||||||
|
@ -20,6 +21,8 @@ import (
|
||||||
"github.com/documize/community/core/api/util"
|
"github.com/documize/community/core/api/util"
|
||||||
"github.com/documize/community/core/log"
|
"github.com/documize/community/core/log"
|
||||||
"github.com/documize/community/core/section/provider"
|
"github.com/documize/community/core/section/provider"
|
||||||
|
"github.com/documize/community/core/utility"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetSections returns available smart sections.
|
// GetSections returns available smart sections.
|
||||||
|
@ -76,8 +79,7 @@ func RunSectionCommand(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshSections updates document sections where the data
|
// RefreshSections updates document sections where the data is externally sourced.
|
||||||
// is externally sourced.
|
|
||||||
func RefreshSections(w http.ResponseWriter, r *http.Request) {
|
func RefreshSections(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "RefreshSections"
|
method := "RefreshSections"
|
||||||
p := request.GetPersister(r)
|
p := request.GetPersister(r)
|
||||||
|
@ -176,3 +178,89 @@ func RefreshSections(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
writeSuccessBytes(w, json)
|
writeSuccessBytes(w, json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************
|
||||||
|
* Reusable Content Blocks
|
||||||
|
**************************************************/
|
||||||
|
|
||||||
|
// AddBlock inserts new reusable content block into database.
|
||||||
|
func AddBlock(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "AddBlock"
|
||||||
|
p := request.GetPersister(r)
|
||||||
|
|
||||||
|
defer utility.Close(r.Body)
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeBadRequestError(w, method, "Bad payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b := entity.Block{}
|
||||||
|
err = json.Unmarshal(body, &b)
|
||||||
|
if err != nil {
|
||||||
|
writePayloadError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.CanUploadDocument(b.LabelID) {
|
||||||
|
writeForbiddenError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.RefID = util.UniqueID()
|
||||||
|
|
||||||
|
tx, err := request.Db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
writeTransactionError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Context.Transaction = tx
|
||||||
|
|
||||||
|
err = p.AddBlock(b)
|
||||||
|
if err != nil {
|
||||||
|
log.IfErr(tx.Rollback())
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.IfErr(tx.Commit())
|
||||||
|
|
||||||
|
writeSuccessEmptyJSON(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlocksForSpace returns available reusable content blocks for the space.
|
||||||
|
func GetBlocksForSpace(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "GetBlocksForSpace"
|
||||||
|
p := request.GetPersister(r)
|
||||||
|
|
||||||
|
params := mux.Vars(r)
|
||||||
|
folderID := params["folderID"]
|
||||||
|
|
||||||
|
if len(folderID) == 0 {
|
||||||
|
writeMissingDataError(w, method, "folderID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var b []entity.Block
|
||||||
|
var err error
|
||||||
|
|
||||||
|
b, err = p.GetBlocksForSpace(folderID)
|
||||||
|
|
||||||
|
if len(b) == 0 {
|
||||||
|
b = []entity.Block{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralSQLError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := json.Marshal(b)
|
||||||
|
if err != nil {
|
||||||
|
writeJSONMarshalError(w, method, "block", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSuccessBytes(w, json)
|
||||||
|
}
|
||||||
|
|
|
@ -186,8 +186,7 @@ type Page struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
ContentType string `json:"contentType"`
|
ContentType string `json:"contentType"`
|
||||||
PageType string `json:"pageType"`
|
PageType string `json:"pageType"`
|
||||||
Preset bool `json:"preset"`
|
BlockID string `json:"blockId"`
|
||||||
PresetID string `json:"presetId"`
|
|
||||||
Level uint64 `json:"level"`
|
Level uint64 `json:"level"`
|
||||||
Sequence float64 `json:"sequence"`
|
Sequence float64 `json:"sequence"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
@ -261,12 +260,23 @@ type Revision struct {
|
||||||
Revisions int `json:"revisions"`
|
Revisions int `json:"revisions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageTemplate represents a section that has been published as a template.
|
// Block represents a section that has been published as a reusable content block.
|
||||||
// We have to create this struct to hold user name.
|
type Block struct {
|
||||||
type PageTemplate struct {
|
BaseEntity
|
||||||
Page
|
OrgID string `json:"orgId"`
|
||||||
Firstname string `json:"firstname"`
|
LabelID string `json:"folderId"`
|
||||||
Lastname string `json:"lastname"`
|
UserID string `json:"userId"`
|
||||||
|
ContentType string `json:"contentType"`
|
||||||
|
PageType string `json:"pageType"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
Excerpt string `json:"excerpt"`
|
||||||
|
RawBody string `json:"rawBody"` // a blob of data
|
||||||
|
Config string `json:"config"` // JSON based custom config for this type
|
||||||
|
ExternalSource bool `json:"externalSource"` // true indicates data sourced externally
|
||||||
|
Used uint64 `json:"used"`
|
||||||
|
Firstname string `json:"firstname"`
|
||||||
|
Lastname string `json:"lastname"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocumentMeta details who viewed the document.
|
// DocumentMeta details who viewed the document.
|
||||||
|
|
141
core/api/request/block.go
Normal file
141
core/api/request/block.go
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||||
|
//
|
||||||
|
// This software (Documize Community Edition) is licensed under
|
||||||
|
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
//
|
||||||
|
// You can operate outside the AGPL restrictions by purchasing
|
||||||
|
// Documize Enterprise Edition and obtaining a commercial license
|
||||||
|
// by contacting <sales@documize.com>.
|
||||||
|
//
|
||||||
|
// https://documize.com
|
||||||
|
|
||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/documize/community/core/api/entity"
|
||||||
|
"github.com/documize/community/core/log"
|
||||||
|
"github.com/documize/community/core/utility"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddBlock saves reusable content block.
|
||||||
|
func (p *Persister) AddBlock(b entity.Block) (err error) {
|
||||||
|
b.OrgID = p.Context.OrgID
|
||||||
|
b.UserID = p.Context.UserID
|
||||||
|
b.Created = time.Now().UTC()
|
||||||
|
b.Revised = time.Now().UTC()
|
||||||
|
|
||||||
|
stmt, err := p.Context.Transaction.Preparex("INSERT INTO block (refid, orgid, labelid, userid, contenttype, pagetype, title, body, excerpt, rawbody, config, externalsource, used, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to prepare insert AddBlock", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = stmt.Exec(b.RefID, b.OrgID, b.LabelID, b.UserID, b.ContentType, b.PageType, b.Title, b.Body, b.Excerpt, b.RawBody, b.Config, b.ExternalSource, b.Used, b.Created, b.Revised)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to execute insert AddBlock", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlock returns requested reusable content block.
|
||||||
|
func (p *Persister) GetBlock(id string) (b entity.Block, err error) {
|
||||||
|
stmt, err := Db.Preparex("SELECT id, refid, orgid, labelid, userid, contenttype, pagetype, title, body, excerpt, rawbody, config, externalsource, used, created, revised FROM block WHERE orgid=? AND refid=?")
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to prepare select GetBlock %s", id), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stmt.Get(&b, p.Context.OrgID, id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to execute select GetBlock %s", id), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlocksForSpace returns all reusable content scoped to given space.
|
||||||
|
func (p *Persister) GetBlocksForSpace(labelID string) (b []entity.Block, err error) {
|
||||||
|
err = Db.Select(&b, "SELECT a.id, a.refid, a.orgid, a.labelid, a.userid, a.contenttype, a.pagetype, a.title, a.body, a.excerpt, a.rawbody, a.config, a.externalsource, a.used, a.created, a.revised, b.firstname, b.lastname FROM block a LEFT JOIN user b ON a.userid = b.refid WHERE orgid=? AND labelid=? ORDER BY a.title", p.Context.OrgID, labelID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to execute select GetBlocksForSpace org %s and label %s", p.Context.OrgID, labelID), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncrementBlockUsage increments usage counter for content block.
|
||||||
|
func (p *Persister) IncrementBlockUsage(id string) (err error) {
|
||||||
|
stmt, err := p.Context.Transaction.Preparex("UPDATE block SET used=used+1, revised=? WHERE orgid=? AND refid=?")
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to prepare update IncrementBlockUsage id %s", id), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = stmt.Exec(time.Now().UTC(), p.Context.OrgID, id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to execute IncrementBlockUsage id %s", id), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecrementBlockUsage decrements usage counter for content block.
|
||||||
|
func (p *Persister) DecrementBlockUsage(id string) (err error) {
|
||||||
|
stmt, err := p.Context.Transaction.Preparex("UPDATE block SET used=used-1, revised=? WHERE orgid=? AND refid=?")
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to prepare update DecrementBlockUsage id %s", id), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = stmt.Exec(time.Now().UTC(), p.Context.OrgID, id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to execute DecrementBlockUsage id %s", id), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateBlock updates existing reusable content block item.
|
||||||
|
func (p *Persister) UpdateBlock(b entity.Block) (err error) {
|
||||||
|
b.Revised = time.Now().UTC()
|
||||||
|
|
||||||
|
var stmt *sqlx.NamedStmt
|
||||||
|
stmt, err = p.Context.Transaction.PrepareNamed("UPDATE block SET title=:title, body=:body, excerpt=:excerpt, rawbody=:rawbody, config=:config, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||||
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to prepare update UpdateBlock %s", b.RefID), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = stmt.Exec(&b)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fmt.Sprintf("Unable to execute update UpdateBlock %s", b.RefID), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBlock removes reusable content block from database.
|
||||||
|
func (p *Persister) DeleteBlock(id string) (rows int64, err error) {
|
||||||
|
return p.Base.DeleteConstrained(p.Context.Transaction, "block", p.Context.OrgID, id)
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ func (p *Persister) AddPage(model models.PageModel) (err error) {
|
||||||
model.Page.Sequence = maxSeq * 2
|
model.Page.Sequence = maxSeq * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt, err := p.Context.Transaction.Preparex("INSERT INTO page (refid, orgid, documentid, userid, contenttype, pagetype, level, title, body, revisions, sequence, preset, presetid, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
stmt, err := p.Context.Transaction.Preparex("INSERT INTO page (refid, orgid, documentid, userid, contenttype, pagetype, level, title, body, revisions, sequence, blockid, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,7 +58,7 @@ func (p *Persister) AddPage(model models.PageModel) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = stmt.Exec(model.Page.RefID, model.Page.OrgID, model.Page.DocumentID, model.Page.UserID, model.Page.ContentType, model.Page.PageType, model.Page.Level, model.Page.Title, model.Page.Body, model.Page.Revisions, model.Page.Sequence, model.Page.Preset, model.Page.PresetID, model.Page.Created, model.Page.Revised)
|
_, err = stmt.Exec(model.Page.RefID, model.Page.OrgID, model.Page.DocumentID, model.Page.UserID, model.Page.ContentType, model.Page.PageType, model.Page.Level, model.Page.Title, model.Page.Body, model.Page.Revisions, model.Page.Sequence, model.Page.BlockID, model.Page.Created, model.Page.Revised)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to execute insert for page", err)
|
log.Error("Unable to execute insert for page", err)
|
||||||
|
@ -89,9 +89,7 @@ func (p *Persister) AddPage(model models.PageModel) (err error) {
|
||||||
|
|
||||||
// GetPage returns the pageID page record from the page table.
|
// GetPage returns the pageID page record from the page table.
|
||||||
func (p *Persister) GetPage(pageID string) (page entity.Page, err error) {
|
func (p *Persister) GetPage(pageID string) (page entity.Page, err error) {
|
||||||
err = nil
|
stmt, err := Db.Preparex("SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.blockid, a.created, a.revised FROM page a WHERE a.orgid=? AND a.refid=?")
|
||||||
|
|
||||||
stmt, err := Db.Preparex("SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.preset, a.presetid, a.created, a.revised FROM page a WHERE a.orgid=? AND a.refid=?")
|
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -111,9 +109,7 @@ func (p *Persister) GetPage(pageID string) (page entity.Page, err error) {
|
||||||
|
|
||||||
// GetPages returns a slice containing all the page records for a given documentID, in presentation sequence.
|
// GetPages returns a slice containing all the page records for a given documentID, in presentation sequence.
|
||||||
func (p *Persister) GetPages(documentID string) (pages []entity.Page, err error) {
|
func (p *Persister) GetPages(documentID string) (pages []entity.Page, err error) {
|
||||||
err = nil
|
err = Db.Select(&pages, "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.blockid, a.created, a.revised FROM page a WHERE a.orgid=? AND a.documentid=? ORDER BY a.sequence", p.Context.OrgID, documentID)
|
||||||
|
|
||||||
err = Db.Select(&pages, "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.preset, a.presetid, a.created, a.revised FROM page a WHERE a.orgid=? AND a.documentid=? ORDER BY a.sequence", p.Context.OrgID, documentID)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("Unable to execute select pages for org %s and document %s", p.Context.OrgID, documentID), err)
|
log.Error(fmt.Sprintf("Unable to execute select pages for org %s and document %s", p.Context.OrgID, documentID), err)
|
||||||
|
@ -126,11 +122,9 @@ func (p *Persister) GetPages(documentID string) (pages []entity.Page, err error)
|
||||||
// GetPagesWhereIn returns a slice, in presentation sequence, containing those page records for a given documentID
|
// GetPagesWhereIn returns a slice, in presentation sequence, containing those page records for a given documentID
|
||||||
// where their refid is in the comma-separated list passed as inPages.
|
// where their refid is in the comma-separated list passed as inPages.
|
||||||
func (p *Persister) GetPagesWhereIn(documentID, inPages string) (pages []entity.Page, err error) {
|
func (p *Persister) GetPagesWhereIn(documentID, inPages string) (pages []entity.Page, err error) {
|
||||||
err = nil
|
|
||||||
|
|
||||||
args := []interface{}{p.Context.OrgID, documentID}
|
args := []interface{}{p.Context.OrgID, documentID}
|
||||||
tempValues := strings.Split(inPages, ",")
|
tempValues := strings.Split(inPages, ",")
|
||||||
sql := "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.preset, a.presetid, a.revisions, a.created, a.revised FROM page a WHERE a.orgid=? AND a.documentid=? AND a.refid IN (?" + strings.Repeat(",?", len(tempValues)-1) + ") ORDER BY sequence"
|
sql := "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.blockid, a.revisions, a.created, a.revised FROM page a WHERE a.orgid=? AND a.documentid=? AND a.refid IN (?" + strings.Repeat(",?", len(tempValues)-1) + ") ORDER BY sequence"
|
||||||
|
|
||||||
inValues := make([]interface{}, len(tempValues))
|
inValues := make([]interface{}, len(tempValues))
|
||||||
|
|
||||||
|
@ -180,7 +174,7 @@ func (p *Persister) GetPagesWhereIn(documentID, inPages string) (pages []entity.
|
||||||
// GetPagesWithoutContent returns a slice containing all the page records for a given documentID, in presentation sequence,
|
// GetPagesWithoutContent returns a slice containing all the page records for a given documentID, in presentation sequence,
|
||||||
// but without the body field (which holds the HTML content).
|
// but without the body field (which holds the HTML content).
|
||||||
func (p *Persister) GetPagesWithoutContent(documentID string) (pages []entity.Page, err error) {
|
func (p *Persister) GetPagesWithoutContent(documentID string) (pages []entity.Page, err error) {
|
||||||
err = Db.Select(&pages, "SELECT id, refid, orgid, documentid, userid, contenttype, pagetype, sequence, level, title, revisions, preset, presetid, created, revised FROM page WHERE orgid=? AND documentid=? ORDER BY sequence", p.Context.OrgID, documentID)
|
err = Db.Select(&pages, "SELECT id, refid, orgid, documentid, userid, contenttype, pagetype, sequence, level, title, revisions, blockid, created, revised FROM page WHERE orgid=? AND documentid=? ORDER BY sequence", p.Context.OrgID, documentID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("Unable to execute select pages for org %s and document %s", p.Context.OrgID, documentID), err)
|
log.Error(fmt.Sprintf("Unable to execute select pages for org %s and document %s", p.Context.OrgID, documentID), err)
|
||||||
|
@ -193,7 +187,6 @@ func (p *Persister) GetPagesWithoutContent(documentID string) (pages []entity.Pa
|
||||||
// UpdatePage saves changes to the database and handles recording of revisions.
|
// UpdatePage saves changes to the database and handles recording of revisions.
|
||||||
// Not all updates result in a revision being recorded hence the parameter.
|
// Not all updates result in a revision being recorded hence the parameter.
|
||||||
func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevision bool) (err error) {
|
func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevision bool) (err error) {
|
||||||
err = nil
|
|
||||||
page.Revised = time.Now().UTC()
|
page.Revised = time.Now().UTC()
|
||||||
|
|
||||||
// Store revision history
|
// Store revision history
|
||||||
|
@ -303,7 +296,6 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis
|
||||||
|
|
||||||
// UpdatePageMeta persists meta information associated with a document page.
|
// UpdatePageMeta persists meta information associated with a document page.
|
||||||
func (p *Persister) UpdatePageMeta(meta entity.PageMeta, updateUserID bool) (err error) {
|
func (p *Persister) UpdatePageMeta(meta entity.PageMeta, updateUserID bool) (err error) {
|
||||||
err = nil
|
|
||||||
meta.Revised = time.Now().UTC()
|
meta.Revised = time.Now().UTC()
|
||||||
|
|
||||||
if updateUserID {
|
if updateUserID {
|
||||||
|
@ -405,8 +397,6 @@ func (p *Persister) DeletePage(documentID, pageID string) (rows int64, err error
|
||||||
|
|
||||||
// GetPageMeta returns the meta information associated with the page.
|
// GetPageMeta returns the meta information associated with the page.
|
||||||
func (p *Persister) GetPageMeta(pageID string) (meta entity.PageMeta, err error) {
|
func (p *Persister) GetPageMeta(pageID string) (meta entity.PageMeta, err error) {
|
||||||
err = nil
|
|
||||||
|
|
||||||
stmt, err := Db.Preparex("SELECT id, pageid, orgid, userid, documentid, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, externalsource, created, revised FROM pagemeta WHERE orgid=? AND pageid=?")
|
stmt, err := Db.Preparex("SELECT id, pageid, orgid, userid, documentid, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, externalsource, created, revised FROM pagemeta WHERE orgid=? AND pageid=?")
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
@ -427,7 +417,6 @@ func (p *Persister) GetPageMeta(pageID string) (meta entity.PageMeta, err error)
|
||||||
|
|
||||||
// GetDocumentPageMeta returns the meta information associated with a document.
|
// GetDocumentPageMeta returns the meta information associated with a document.
|
||||||
func (p *Persister) GetDocumentPageMeta(documentID string, externalSourceOnly bool) (meta []entity.PageMeta, err error) {
|
func (p *Persister) GetDocumentPageMeta(documentID string, externalSourceOnly bool) (meta []entity.PageMeta, err error) {
|
||||||
err = nil
|
|
||||||
filter := ""
|
filter := ""
|
||||||
if externalSourceOnly {
|
if externalSourceOnly {
|
||||||
filter = " AND externalsource=1"
|
filter = " AND externalsource=1"
|
||||||
|
@ -507,24 +496,3 @@ func (p *Persister) DeletePageRevisions(pageID string) (rows int64, err error) {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************
|
|
||||||
* Section templates
|
|
||||||
********************/
|
|
||||||
|
|
||||||
// GetSpaceSectionTemplates returns a slice all saved section templates.
|
|
||||||
func (p *Persister) GetSpaceSectionTemplates(folderID string) (pages []entity.PageTemplate, err error) {
|
|
||||||
err = Db.Select(&pages, `SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.preset, a.presetid, a.created, a.revised, u.firstname, u.lastname
|
|
||||||
FROM page a
|
|
||||||
LEFT JOIN document b ON a.documentid = b.refid
|
|
||||||
LEFT JOIN user u ON a.userid = u.refid
|
|
||||||
WHERE a.orgid=? AND b.labelid=? AND a.preset=1
|
|
||||||
ORDER BY a.title`, p.Context.OrgID, folderID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error(fmt.Sprintf("Unable to execute GetSpaceSectionTemplates for org %s and space %s", p.Context.OrgID, folderID), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
@ -56,8 +56,6 @@ func (p *Persister) AddPin(pin entity.Pin) (err error) {
|
||||||
|
|
||||||
// GetPin returns requested pinned item.
|
// GetPin returns requested pinned item.
|
||||||
func (p *Persister) GetPin(id string) (pin entity.Pin, err error) {
|
func (p *Persister) GetPin(id string) (pin entity.Pin, err error) {
|
||||||
err = nil
|
|
||||||
|
|
||||||
stmt, err := Db.Preparex("SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND refid=?")
|
stmt, err := Db.Preparex("SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND refid=?")
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
@ -90,7 +88,6 @@ func (p *Persister) GetUserPins(userID string) (pins []entity.Pin, err error) {
|
||||||
|
|
||||||
// UpdatePin updates existing pinned item.
|
// UpdatePin updates existing pinned item.
|
||||||
func (p *Persister) UpdatePin(pin entity.Pin) (err error) {
|
func (p *Persister) UpdatePin(pin entity.Pin) (err error) {
|
||||||
err = nil
|
|
||||||
pin.Revised = time.Now().UTC()
|
pin.Revised = time.Now().UTC()
|
||||||
|
|
||||||
var stmt *sqlx.NamedStmt
|
var stmt *sqlx.NamedStmt
|
||||||
|
@ -114,8 +111,6 @@ func (p *Persister) UpdatePin(pin entity.Pin) (err error) {
|
||||||
|
|
||||||
// UpdatePinSequence updates existing pinned item sequence number
|
// UpdatePinSequence updates existing pinned item sequence number
|
||||||
func (p *Persister) UpdatePinSequence(pinID string, sequence int) (err error) {
|
func (p *Persister) UpdatePinSequence(pinID string, sequence int) (err error) {
|
||||||
err = nil
|
|
||||||
|
|
||||||
stmt, err := p.Context.Transaction.Preparex("UPDATE pin SET sequence=?, revised=? WHERE orgid=? AND userid=? AND refid=?")
|
stmt, err := p.Context.Transaction.Preparex("UPDATE pin SET sequence=?, revised=? WHERE orgid=? AND userid=? AND refid=?")
|
||||||
defer utility.Close(stmt)
|
defer utility.Close(stmt)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,31 @@
|
||||||
/* community edition */
|
/* community edition */
|
||||||
ALTER TABLE page ADD COLUMN `preset` BOOL NOT NULL DEFAULT 0 AFTER `pagetype`;
|
DROP TABLE IF EXISTS `block`;
|
||||||
ALTER TABLE page ADD COLUMN `presetid` CHAR(16) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `preset`;
|
|
||||||
|
|
||||||
/* Note:
|
CREATE TABLE IF NOT EXISTS `block` (
|
||||||
Preset data is not required in pagemeta as a simple join to page will surface these fields.
|
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
Version history table does not need these fields as they are populated once during page creation:
|
`refid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||||
-- you cannot mark an existing section as a preset
|
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
|
||||||
-- a page is only marked as preset during it's creation (e.g. created from an existing preset)
|
`labelid` CHAR(16) DEFAULT '' COLLATE utf8_bin,
|
||||||
|
`userid` CHAR(16) DEFAULT '' COLLATE utf8_bin,
|
||||||
|
`contenttype` CHAR(20) NOT NULL DEFAULT 'wysiwyg',
|
||||||
|
`pagetype` CHAR(10) NOT NULL DEFAULT 'section',
|
||||||
|
`title` NVARCHAR(2000) NOT NULL,
|
||||||
|
`body` LONGTEXT,
|
||||||
|
`excerpt` NVARCHAR(2000) NOT NULL,
|
||||||
|
`used` INT UNSIGNED NOT NULL,
|
||||||
|
`rawbody` LONGBLOB,
|
||||||
|
`config` JSON,
|
||||||
|
`externalsource` BOOL DEFAULT 0,
|
||||||
|
`created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT pk_id PRIMARY KEY (id),
|
||||||
|
INDEX `idx_block_refid` (`refid` ASC),
|
||||||
|
INDEX `idx_block_labelid` (`labelid` ASC))
|
||||||
|
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
|
||||||
|
ENGINE = InnoDB;
|
||||||
|
|
||||||
|
ALTER TABLE page ADD COLUMN `blockid` CHAR(16) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `pagetype`;
|
||||||
|
/* Note: version history table does not need blockid field as they are populated once during page creation:
|
||||||
|
- you cannot mark an existing section as a preset
|
||||||
|
- a page is only marked as preset during it's creation (e.g. created from an existing preset)
|
||||||
*/
|
*/
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue