/*
* Copyright 2014 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This class is the representation of a content.
*/
Ext.define(
"Ametys.cms.content.Content",
{
config: {
/**
* @cfg {String} id The unique id of the content
*/
/**
* @method getId Get the #cfg-id
* @return {String} The id
*/
/** @ignore */
id: null,
/**
* @cfg {String} title The title of the content
*/
/**
* @method getTitle Get the #cfg-title
* @return {String} The title
*/
/** @ignore */
title: null,
/**
* @cfg {Object} titleVariants The title of each language if title is a multilingual string. Null otherwise.
*/
/**
* @method getTitleVariants Get the #cfg-titleVariants
* @return {Object} The title variants for each languages. Null if title is not multilingual.
*/
/** @ignore */
titleVariants: null,
/**
* @cfg {String} path The path in the repository of the content
*/
/**
* @method getPath Get the #cfg-path
* @return {String} The path
*/
/** @ignore */
path: null,
/**
* @cfg {String} lang The lang of the content
*/
/**
* @method getLang Get the #cfg-lang
* @return {String} The lang
*/
/** @ignore */
lang: null,
/**
* @cfg {String} name The name of the content
*/
/**
* @method getName Get the #cfg-name
* @return {String} The name
*/
/** @ignore */
name: null,
/**
* @cfg {String[]} types The content types
*/
/**
* @method getTypes Get the #cfg-types
* @return {String[]} The types
*/
/** @ignore */
types: [],
/**
* @cfg {String[]} mixins The mixins
*/
/**
* @method getMixins Get the #cfg-mixins
* @return {String[]} The mixins
*/
/** @ignore */
mixins: [],
/**
* @cfg {String} workflowName The identifier of the workflow used for this content
*/
/**
* @method getWorkflowName Get the #cfg-workflowName
* @return {String} The workflow name
*/
/** @ignore */
workflowName: null,
/**
* @cfg {String} exists True if the content still exists
*/
/**
* @method getExists Get the #cfg-exists
* @return {String} The exits status
*/
/** @ignore */
exists: false,
/**
* @cfg {Number[]} workflowSteps The arrays of current workflow steps
*/
/**
* @method getWorkflowSteps Get the #cfg-workflowSteps
* @return {Number[]} The worfklow steps
*/
/** @ignore */
workflowSteps: [],
/**
* @cfg {Number[]} availableActions The arrays of current available action
*/
/**
* @method getAvailableActions Get the #cfg-availableActions
* @return {Number} The available actions
*/
/** @ignore */
availableActions: [],
/**
* @cfg {boolean} isModifiable True if this content can be modified. False if it read-only: this is not about rights. Can be false for a virtual content dynamically created by reading a RSS or a database... but basically not stored in JCR
*/
/**
* @method getIsModifiable Get the #cfg-isModifiable
* @return {boolean} The is modifiable
*/
/** @ignore */
isModifiable: false,
/**
* @cfg {boolean} isSimple True if this content is a simple content type.
*/
/**
* @method getIsSimple Get the #cfg-isSimple
* @return {boolean} The is simple
*/
/** @ignore */
isSimple: false,
/**
* @cfg {boolean} isReferenceTable True if this content is a reference table's entry.
*/
/**
* @method getIsReferenceTable Get the #isReferenceTable
* @return {boolean} The is reference table
*/
/** @ignore */
isReferenceTable: false,
/**
* @cfg {String} parent The parent of this content (if defined). Always null for a content which is not reference table entry
*/
/**
* @method getParent Get the #cfg-parent
* @return {String} The parent
*/
/** @ignore */
parent: null,
/**
* @cfg {String[]} rights List of the id of the rights the current user have on this content
*/
/**
* @method getRights Get the #cfg-rights
* @return {String[]} The rights
*/
/** @ignore */
rights: [],
/**
* @cfg {Boolean} locked True if the content is locked
*/
/**
* @method getLocked Get the #cfg-locked
* @return {Boolean} The locked state
*/
/** @ignore */
locked: false,
/**
* @cfg {String} lockOwner The login of lock owner. Can be null is the content is not locked.
*/
/**
* @method getLockOwner Get the #cfg-lockOwner
* @return {String} The lock owner
*/
/** @ignore */
lockOwner: null,
/**
* @cfg {Boolean} canUnlock On a locked content, `true` if the current user can unlock it.
*/
/**
* @method canUnlock Get the #cfg-lockOwner
* @return {Boolean} On a locked content, `true` if the current user can unlock it.
*/
/** @ignore */
canUnlock: false,
/**
* @cfg {String} lastContributor The login of last contributor.
*/
/**
* @method getLastContributor Get the #cfg-lastContributor
* @return {String} The last contributor
*/
/** @ignore */
lastContributor: null,
/**
* @cfg {String} lastModified The last modified date as String.
*/
/**
* @method getLastModified Get the #cfg-lastModified
* @return {String} The last modified
*/
/** @ignore */
lastModified: null,
/**
* @cfg {String} creationDate The creation date as String
*/
/**
* @method getCreationDate Get the #cfg-creationDate
* @return {String} The creation date
*/
/** @ignore */
creationDate: null,
/**
* @cfg {Object} additionalData The additional data
*/
/**
* @method getAdditionalData Get the #cfg-additionalData
* @return {Object} The additional data
*/
additionalData: {},
/**
* @cfg {Number} contentWidth The width of content. Determines the fixed width of rich texts when editing the content. Set to 0 to not fix width.
*/
/**
* @method getContentWidth Get the #cfg-contentWidth
* @return {Number} The width of content or 0 is the width is not fixed.
*/
/** @ignore */
contentWidth: 0,
/**
* @cfg {boolean} isTaggable True if this content can be tagged.
*/
/**
* @method getIsTaggable Get the #cfg-isTaggable
* @return {boolean} The page is taggable
*/
/** @ignore */
isTaggable: false,
/**
* @cfg {String} scheduledArchivingDate the scheduled archiving date as String (or null if none).
*/
/**
* @method getScheduledArchivingDate Get the #cfg-scheduledArchivingDate
* @return {String} The scheduled archiving date as String (or null if none)
*/
/** @ignore */
scheduledArchivingDate: null,
/**
* @cfg {Number} reportsCount the number of reports.
*/
/**
* @method getReportsCount Get the #cfg-reportsCount
* @return {Number} The number of reports
*/
/** @ignore */
reportsCount: 0,
/**
* @cfg {String} [messagetTarget=Ametys.message.MessageTarget#CONTENT]
*/
messageTarget: null
},
/** @property {String[]} _ancestorsOrSelfTypes The ancestors or self types */
_ancestorsOrSelfTypes: null,
/** @property {String[]} _ancestorsOrSelfMixins The ancestors or self mixins */
_ancestorsOrSelfMixins: null,
/**
* Creates a content instance
* @param {Object} config See configuration doc.
*/
constructor: function (config)
{
this.initConfig(config);
this._messageTarget = config.messageTarget || Ametys.message.MessageTarget.CONTENT;
},
/**
* Determines if the current user has the specified right on the content
* @param {String} rightId The identifier of the right to check
* @return {boolean} True or false
*/
hasRight: function(rightId)
{
return Ext.Array.contains(this._rights, rightId);
},
/**
* Try to lock the content.
* If the content was already locked, the callback is called with 'true' as argument
* @param {Function} callback The method to call
* @param {boolean} callback.success true if the lock was a success, else false (and a message was already displayed to the user)
* @param {boolean} force true to force lock without checking current state
*/
lock: function(callback, force)
{
if (force === true || !this._locked)
{
// Try to lock the content
Ametys.data.ServerComm.callMethod({
role: "org.ametys.cms.lock.LockContentManager",
methodName: "unlockOrLock",
parameters: [[this._id], 'lock'],
callback: {
scope: this,
handler: this._lockCB,
arguments: {callback: callback}
},
errorMessage: {
msg: "{{i18n CONTENT_LOCK_ERROR}}",
category: 'Ametys.cms.content.Content'
}
});
}
else if (Ext.isFunction(callback))
{
callback(true);
}
},
/**
* Try to unlock the content.
* If the content was already locked, the callback is called with 'true' as argument
* @param {Function} callback The method to call
* @param {boolean} callback.success true if the lock was a success, else false (and a message was already displayed to the user)
* @param {boolean} force true to force unlock without checking current state
*/
unlock: function(callback, force)
{
if (force === true || this._locked)
{
// Try to unlock the content
Ametys.data.ServerComm.callMethod({
role: "org.ametys.cms.lock.LockContentManager",
methodName: "unlockOrLock",
parameters: [[this._id], 'unlock'],
callback: {
scope: this,
handler: this._lockCB,
arguments: {callback: callback}
},
errorMessage: {
msg: "{{i18n CONTENT_LOCK_ERROR}}",
category: 'Ametys.cms.content.Content'
}
});
}
else if (Ext.isFunction(callback))
{
callback(true);
}
},
/**
* @private
* Callback of #lock
* @param {Object[]} response the server response
* @param {String} response.mode the mode ( unlock or lock )
* @param {String[]} response.unlocked-contents-id the ids of the unlocked contents
* @param {String[]} response.unlocked-contents the unlocked contents
* @param {String[]} response.still-locked-contents the contents that are still locked
* @param {String[]} response.fail-locked-contents the contents that failed to be locked
* @param {String[]} response.locked-contents-id the ids of the locked contents
* @param {String[]} response.locked-contents the locked contents
* @param {String[]} response.already-locked-contents the contents already locked
* @param {String[]} response.fail-unlocked-contents the contents that failed to be unlocked
* @param {Object[]} args the callback arguments
* @param {Function} args.callback the callback to call
*/
_lockCB: function(response, args)
{
var callback = args['callback'];
var unlockMode = response['mode'] == 'unlock';
if (unlockMode)
{
var success = true;
var unlockedContents = response['unlocked-contents'];
var stillLockedContents = response['still-locked-contents'];
var failLockedContents = response['fail-unlocked-contents'];
var msg = "";
if (stillLockedContents != "" || failLockedContents != "")
{
if (unlockedContents != "")
{
msg += "{{i18n CONTENT_UNLOCK_ACTION_UNLOCKED_CONTENTS}}" + unlockedContents;
}
if (stillLockedContents != "")
{
if (msg != '')
{
msg + "<br/><br/>";
}
msg += "{{i18n CONTENT_UNLOCK_ACTION_STILL_LOCKED_CONTENTS}}" + stillLockedContents;
}
if (failLockedContents != "")
{
if (msg != '')
{
msg + "<br/><br/>";
}
msg += "{{i18n CONTENT_UNLOCK_ACTION_FAILED_CONTENTS}}" + failLockedContents;
}
Ametys.log.ErrorDialog.display({
title: "{{i18n CONTENT_UNLOCK_ACTION}}",
text: msg,
details: "",
category: "Ametys.plugins.cms.content.controller.LockController.act"
});
success = false;
}
var unlockedContentIds = response["unlocked-contents-id"].split(',');
if (unlockedContentIds.length > 0 && unlockedContentIds[0])
{
this._locked = false;
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.LOCK_CHANGED,
targets: {
id: this._messageTarget,
parameters: { ids: unlockedContentIds }
}
});
}
if (Ext.isFunction(callback))
{
callback(success);
}
}
else
{
var success = true;
var lockedContents = response['locked-contents'];
var alreadyLockedContents = response['already-locked-contents'];
var failUnlockedContents = response['fail-locked-contents'];
if (alreadyLockedContents != "" || failUnlockedContents != "")
{
var msg = "";
if (lockedContents != "")
{
msg += "{{i18n CONTENT_LOCK_ACTION_LOCKED_CONTENTS}}" + lockedContents;
}
if (alreadyLockedContents != "")
{
if (msg != '')
{
msg + "<br/><br/>";
}
msg += "{{i18n CONTENT_LOCK_ACTION_ALREADY_LOCKED_CONTENTS}}" + alreadyLockedContents;
}
if (failUnlockedContents != "")
{
if (msg != '')
{
msg + "<br/><br/>";
}
msg += "{{i18n CONTENT_LOCK_ACTION_FAILED_CONTENTS}}" + failUnlockedContents;
}
Ametys.log.ErrorDialog.display({
title: "{{i18n CONTENT_LOCK_ACTION}}",
text: msg,
details: "",
category: "Ametys.plugins.cms.content.controller.LockController.act"
});
success = false;
}
var lockedContentIds = response['locked-contents-id'].split(',');
if (lockedContentIds.length > 0 && lockedContentIds[0])
{
this._locked = true;
this._lockOwner = response['lockOwner'];
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.LOCK_CHANGED,
targets: {
id: this._messageTarget,
parameters: { ids: lockedContentIds }
}
});
}
if (Ext.isFunction(callback))
{
callback(success);
}
}
},
/**
* Get the tab of ancestors content types and itself
* @return {String[]} The tab of ancestors content types and itself
*/
getAncestorsOrSelfTypes: function()
{
if (!this._ancestorsOrSelfTypes)
{
this._ancestorsOrSelfTypes = [];
Ext.Array.each(this._types, function(contentId)
{
var contentType = Ametys.cms.content.ContentTypeDAO.getContentType(contentId);
contentType.getAncestorsOrSelf().each(function(ancestorContent)
{
if (!Ext.Array.contains(this._ancestorsOrSelfTypes, ancestorContent.get("id")))
{
this._ancestorsOrSelfTypes.push(ancestorContent.get("id"));
}
}, this);
}, this);
}
return this._ancestorsOrSelfTypes;
},
/**
* Get the tab of ancestors mixins and itself
* @return {String[]} The tab of ancestors mixins and itself
*/
getAncestorsOrSelfMixins: function()
{
if (!this._ancestorsOrSelfMixins)
{
this._ancestorsOrSelfMixins = [];
Ext.Array.each(this._mixins, function(contentId)
{
var contentType = Ametys.cms.content.ContentTypeDAO.getContentType(contentId);
contentType.getAncestorsOrSelf().each(function(ancestorContent)
{
if (!Ext.Array.contains(this._ancestorsOrSelfMixins, ancestorContent.get("id")))
{
this._ancestorsOrSelfMixins.push(ancestorContent.get("id"));
}
}, this);
}, this);
}
return this._ancestorsOrSelfMixins;
},
/**
* Get the content's properties
* @return {Object} The content's properties
*/
getProperties: function (initialProperty)
{
return Ext.apply ({
id: this._id,
name: this._name,
title: this._title,
path: this._path,
lang: this._lang,
types: this._types,
ancestorsOrSelfTypes: this.getAncestorsOrSelfTypes(),
ancestorsOrSelfMixins: this.getAncestorsOrSelfMixins(),
mixins: this._mixins,
workflowName : this._workflowName,
workflowSteps : this._workflowSteps,
isModifiable : this._isModifiable,
isReferenceTable: this._isReferenceTable,
isSimple: this._isSimple,
parent: this._parent,
rights: this._rights,
availableActions: this._availableActions,
additionalData: this._additionalData,
contentWidth: this._contentWidth,
reportsCount: this._reportsCount
}, initialProperty
);
}
}
);