/*
* Copyright 2020 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.
*/
/**
* Singleton class defining the file import function.
* @private
*/
Ext.define('Ametys.plugins.contentio.ConfigureCSVImport', {
singleton: true,
/**
* @cfg {String} [helperServerRole="org.ametys.plugins.contentio.csv.ImportCSVFileHelper"] The role of server component which prepares the import
*/
/**
* @property {Ext.form.Panel} _formPanel The dialog box form panel.
* @private
*/
_formPanel: null,
/**
* @property {Ametys.window.DialogBox} _box The action dialog box.
* @private
*/
_box: null,
/**
* @property {Object} _results The results of the previous dialog box.
* @private
*/
_results: null,
/**
* @property {Object} _parameters The default parameters for the dialog box.
* @private
*/
_parameters: null,
/**
* @property {Object} _grid The content attributes mapping grid.
* @private
*/
_grid: null,
/**
* Open the configuration dialog for CSV import
* @param {Object} config the configuration object
*/
open: function(config)
{
this.helperServerRole = config.helperServerRole || "org.ametys.plugins.contentio.csv.ImportCSVFileHelper";
this._initialize(config)
this._box.show();
},
/**
* Create the import dialog box.
* @param {Object} config the configuration object
* @private
*/
_initialize: function(config)
{
this._formPanel = this._createFormPanel(config);
this._box = Ext.create('Ametys.window.DialogBox', {
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_CONFIG_DIALOG_TITLE}}",
iconCls: 'ametysicon-gear39',
layout: {
type: 'vbox',
align : 'stretch',
pack : 'start'
},
width: 700,
maxHeight: 800,
items: [this._formPanel],
closeAction: 'destroy',
buttons: [{
text: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_OK}}",
handler: Ext.bind(this._ok, this, [config], 0),
scope: this
}, {
text: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CANCEL}}",
handler: Ext.bind(this._cancel, this, [config], 0),
scope: this
}]
});
SolrHint.init();
return true;
},
/**
* Create the upload dialog's form panel.
* @param {Object} config the configuration object
* @return {String} The upload dialog's form panel.
* @private
*/
_createFormPanel: function(config)
{
var items = [];
items.push({
fieldLabel: "* {{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CREATION_LABEL}}",
ametysDescription: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CREATION_DESCRIPTION}}",
hidden: config['create-action'],
value: (config['create-action'] === undefined) ? 1 : config['create-action'],
xtype: "numberfield",
name: 'createAction',
allowBlank: false
});
items.push({
fieldLabel: "* {{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_EDIT_LABEL}}",
ametysDescription: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_EDIT_DESCRIPTION}}",
hidden: config['edit-action'],
value: (config['edit-action'] === undefined) ? 2 : config['edit-action'],
xtype: "numberfield",
name: 'editAction',
allowBlank: false
});
items.push({
fieldLabel: "* {{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CYCLE_LABEL}}",
ametysDescription: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CYCLE_DESCRIPTION}}",
hidden: config['workflow-name'],
value: (config['workflow-name'] === undefined) ? config.defaultWorkflow : config['workflow-name'],
xtype: "combobox",
forceSelection: true,
store: {
fields: ['label', 'value'],
data: config.workflows,
sorters: [{
property: 'label',
direction: 'ASC'
}]
},
queryMode: 'local',
displayField: 'label',
valueField: 'value',
name: 'workflow',
allowBlank: false
});
items.push(Ametys.cms.language.LanguageDAO.createComboBox({
name: 'language',
hidden: config['content-language'],
value: config['content-language'],
fieldLabel: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_LANGUAGE_LABEL}}",
ametysDescription: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_LANGUAGE_DESCRIPTION}}"
}));
items.push({
value: "CREATE_AND_UPDATE",
xtype: "combobox",
forceSelection: true,
store: {
fields: ['label', 'value'],
data: config.synchronizeModes
},
fieldLabel: "* {{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_SYNCHRONIZE_MODE_LABEL}}",
ametysDescription: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_SYNCHRONIZE_MODE_DESCRIPTION}}",
queryMode: 'local',
displayField: 'label',
valueField: 'value',
name: 'importMode',
allowBlank: false
});
this._grid = this._getGridMapping(config);
items.push(this._grid)
return Ext.create('Ext.form.Panel', {
flex: 1,
bodyStyle: 'padding:5px',
defaultType: 'textfield',
defaults: {
cls: 'ametys',
labelSeparator: '',
labelAlign: 'right',
labelWidth: 200,
anchor: '100%'
},
items: items,
border: false,
scrollable: 'y'
});
},
_getGridValues: function()
{
var me = this,
value = [];
this._grid.getStore().getData().each(function(record) {
var v = me._getValueFromRecord(record);
if (v != null)
{
v.attributePath = v.attributePath.trim()
value.push(v);
}
}, this);
return value;
},
_getGridMapping: function (config)
{
this._store = Ext.create('Ext.data.Store', {
fields:[
{name: 'header', type: 'string'},
{
name: 'attributePath',
type: 'string',
defaultValue: '',
convert: function (value) {
return value.replace('/', '.');
}
},
{name: 'isId', type: 'boolean', defaultValue: false}
],
data: config.mapping
});
var grid = Ext.create('Ext.grid.Panel', {
flex: 1,
fieldLabel: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CORRESPONDANCE_LABEL}}",
store: this._store,
disableSelection: true,
viewConfig: {
markDirty: false
},
columns: [
{
text: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_HEADER_LABEL}}",
tooltip: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_HEADER_DESCRIPTION}}",
flex: 0.8,
dataIndex: 'header'
},
{
text: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CONTENT_ATTRIBUTE_LABEL}}",
tooltip: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_CONTENT_ATTRIBUTE_DESCRIPTION}}",
dataIndex: 'attributePath',
name: 'contentatt',
xtype: 'widgetcolumn',
flex: 1,
widget: {
xtype: 'solr-code',
mode: 'solr-ametys-columns',
height: 30,
listeners: {
'blur': Ext.bind(this._onWidgetChange, this, ['attributePath'], 0)
},
singleLine: true,
ctypes: [config.contentType],
cmParams: {
extraKeys: {
'Tab': 'autocomplete'
},
hintOptions: {
allowAllOption: false,
allowCommonOption: false
}
}
}
},
{
text: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_ID_LABEL}}",
tooltip: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_ID_DESCRIPTION}}",
dataIndex: 'isId',
xtype: 'widgetcolumn',
widget: {
xtype: 'checkbox',
listeners: {
'change': Ext.bind(this._onWidgetChange, this, ['isId'], 0)
}
}
}
]
});
// We have to update the grid manually, as otherwise the size is falsely computed due to code xtype
grid.addListener("afterlayout", function() {
this.update();
}, grid, {single: true})
return grid;
},
/**
* Get the values associated to a record
* @param {Ext.data.Model} record The record to analyser
* @return {Object} An object of the data of the record
*/
_getValueFromRecord: function (record)
{
return Ext.clone(record.getData());
},
/**
* @private
* Listener when a widget value has changed, in order to update the grid store.
* @param {String} fieldName The name of the field to update in the record
* @param {Ext.form.field.Field} field The field
*/
_onWidgetChange: function(fieldName, field)
{
if (field.getWidgetRecord)
{
var rec = field.getWidgetRecord();
rec.set(fieldName, field.getValue());
}
},
/**
* Handle the OK button by submitting the form.
* @param {Object} config the configuration object
* @private
*/
_ok: function(config)
{
var form = this._formPanel.getForm();
var gridValues = this._getGridValues();
var contentAttributeArray = [];
var contentIdArray = [];
var noId = true;
for(var i = 0; i < gridValues.length; i++) {
var row = gridValues[i];
var attributePath = row.attributePath;
if(attributePath != "")
{
if(contentAttributeArray.indexOf(attributePath) == -1)
{
contentAttributeArray.push(attributePath)
}
else
{
Ametys.Msg.show ({
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_SAME_CONTENT}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
var index = attributePath.lastIndexOf("."); // Gets the last index where a dot occurs
if(row.isId)
{
noId = false;
contentIdArray.push(attributePath.substring(0, index))
}
}
};
var formValues = this._formPanel.getValues();
if (noId)
{
Ametys.Msg.show ({
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_MISSING_ID}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
if (!form.isValid())
{
return;
}
Ametys.data.ServerComm.callMethod({
role: this.helperServerRole,
methodName: "validateConfiguration",
parameters: [config.contentType, formValues, gridValues],
callback: {
handler: this._validateCB,
arguments: {
config: config,
formValues: formValues,
gridValues: gridValues
},
scope: this
},
errorMessage: {
category: this.self.getName(),
msg: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TEXT}}", config.fileName)
}
});
},
_validateCB: function(result, args)
{
if(result.error == undefined)
{
Ametys.data.ServerComm.callMethod({
role: this.helperServerRole,
methodName: "importContents",
priority: Ametys.data.ServerComm.PRIORITY_LONG_REQUEST,
parameters: [args.config, args.formValues, args.gridValues],
callback: {
handler: this._importCB,
arguments: {
},
scope: this
},
errorMessage: {
category: this.self.getName(),
msg: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TEXT}}", args.config.fileName)
}
});
Ametys.notify({
type: 'info',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_BACKGROUND}}", args.config.fileName, result.contentTypeName)
});
this._box.hide();
}
else
{
var errorMsg = "";
var msg = result.error;
if (msg == 'missing-id')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_MISSING_ID}}", result.details);
}
else if (msg == 'missing-id-content')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_MISSING_ID_CONTENT}}", result.details[0], result.details[1]);
}
else if (msg == 'bad-mapping')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_MAPPING_DETAILED}}", result.details[0], result.details[1]);
}
else if (msg == 'cant-create-view')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_CANT_CREATE_VIEW}}", result.details);
}
else if (msg == 'unknown-type')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_UNKNOWN_TYPE}}", result.details);
}
else if (msg == 'string-as-container')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_STRING_AS_CONTAINER}}", result.details);
}
else if (msg == 'multiple-content-inside-repeater')
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_MULTIPLE_CONTAINER_INSIDE_REPEATER}}", result.details[0], result.details[1]);
}
else
{
errorMsg = Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TEXT}}", args.config.fileName);
}
Ametys.Msg.show({
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TITLE}}",
msg: errorMsg,
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
},
_importCB: function(result)
{
if(!result.error)
{
if(result.nbErrors == 0 && result.nbWarnings == 0)
{
Ametys.notify({
type: 'info',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_SUCCESS}}", result.fileName, result.importedCount)
});
}
else if(result.nbWarnings == 0)
{
Ametys.notify({
type: 'warn',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_PARTIAL_SUCCESS_ERRORS}}", result.fileName, result.importedCount, result.nbErrors)
});
}
else if(result.nbErrors == 0)
{
Ametys.notify({
type: 'warn',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_PARTIAL_SUCCESS_WARNINGS}}", result.fileName, result.importedCount, result.nbWarnings)
});
}
else
{
Ametys.notify({
type: 'warn',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_PARTIAL_SUCCESS_ERRORS_AND_WARNINGS}}", result.fileName, result.importedCount, result.nbWarnings, result.nbErrors)
});
}
}
else if(result.error == "no-import")
{
Ametys.notify({
type: 'error',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_NO_IMPORT}}", result.fileName)
});
}
else
{
Ametys.notify({
type: 'error',
title: "{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_DIALOG_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CONTENTIO_CONTENT_IMPORT_ERROR_TEXT}}", result.fileName)
});
}
},
/**
* Handle the cancel button by hiding the dialog box.
* @param {Object} config the configuration object
* @private
*/
_cancel: function(config)
{
Ametys.data.ServerComm.callMethod({
role: this.helperServerRole,
methodName: "cancelImport",
parameters: [config.importId],
errorMessage: false // This calls is to allow server to do some clean up. No impact on user
});
this._box.hide();
}
});