forked from extern/egroupware
0a91bc5aa9
Filterable fields are attempted to be autodetected by using the exportable fields. Records can be filtered by fields with type select,select-cat,select-account,date,date-time (according to egw_record class) only at this time. Filters are saved in the definition and used with scheduled exports. They are also available to the user for modification in the export dialog.
1029 lines
33 KiB
PHP
1029 lines
33 KiB
PHP
<?php
|
|
/**
|
|
* eGroupWare - importexport
|
|
*
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @package importexport
|
|
* @link http://www.egroupware.org
|
|
* @author Cornelius Weiss <nelius@cwtech.de>
|
|
* @copyright Cornelius Weiss <nelius@cwtech.de>
|
|
* @version $Id$
|
|
*/
|
|
|
|
/**
|
|
* Userinterface to define {im|ex}ports
|
|
*
|
|
* @package importexport
|
|
*/
|
|
class importexport_definitions_ui
|
|
{
|
|
const _debug = false;
|
|
|
|
const _appname = 'importexport';
|
|
|
|
public $public_functions = array(
|
|
'edit' => true,
|
|
'index' => true,
|
|
'wizard' => true,
|
|
'import_definition' => true,
|
|
'site_config' => true,
|
|
);
|
|
|
|
/**
|
|
* holds all available plugins
|
|
*
|
|
* @var array
|
|
*/
|
|
var $plugins;
|
|
|
|
/**
|
|
* holds user chosen plugin after step20
|
|
*
|
|
* @var object
|
|
*/
|
|
var $plugin;
|
|
|
|
/**
|
|
* xajax response object
|
|
*
|
|
* @var object
|
|
*/
|
|
var $response = true;
|
|
|
|
function __construct()
|
|
{
|
|
// we cant deal with notice and warnings, as we are on ajax!
|
|
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
|
$GLOBALS['egw']->translation->add_app(self::_appname);
|
|
$GLOBALS['egw_info']['flags']['currentapp'] = self::_appname;
|
|
|
|
$GLOBALS['egw_info']['flags']['include_xajax'] = true;
|
|
$this->etpl = new etemplate();
|
|
$this->clock = html::image(self::_appname,'clock');
|
|
$this->steps = array(
|
|
'wizard_step10' => lang('Choose an application'),
|
|
'wizard_step20' => lang('Choose a plugin'),
|
|
'wizard_step21' => lang('Choose a name for this definition'),
|
|
'wizard_step90' => lang('Which users are allowed to use this definition'),
|
|
'wizard_finish' => '',
|
|
);
|
|
//register plugins
|
|
$this->plugins = importexport_helper_functions::get_plugins();
|
|
}
|
|
|
|
/**
|
|
* List defined {im|ex}ports
|
|
*
|
|
* @param array $content=null
|
|
*/
|
|
function index($content = null,$msg='')
|
|
{
|
|
$filter = array('name' => '*');
|
|
|
|
if($GLOBALS['egw_info']['user']['apps']['admin']) {
|
|
// Any public definition
|
|
$filter[] = '(owner=0 OR owner IS NULL OR allowed_users IS NOT NULL OR owner = ' . $GLOBALS['egw_info']['user']['account_id'] . ')';
|
|
} else {
|
|
// Filter private definitions
|
|
$filter['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
|
$config = config::read('phpgwapi');
|
|
if($config['export_limit'] == 'no' && !bo_merge::is_export_limit_excepted()) {
|
|
$filter['type'] = 'import';
|
|
}
|
|
}
|
|
|
|
if (is_array($content))
|
|
{
|
|
// Handle legacy actions
|
|
if (isset($content['nm']['rows']['delete']))
|
|
{
|
|
$content['nm']['action'] = 'delete';
|
|
$content['nm']['selected'] = array_keys($content['nm']['rows']['delete'],'pressed');
|
|
}
|
|
elseif(($button = array_search('pressed',$content['nm']['rows'])) !== false)
|
|
{
|
|
$selected = $content['nm']['rows']['selected'];
|
|
if(count($selected) < 1 || !is_array($selected)) common::egw_exit();
|
|
switch ($button)
|
|
{
|
|
case 'delete_selected' :
|
|
$content['nm']['selected'] = $selected;
|
|
$content['nm']['action'] = 'delete';
|
|
break;
|
|
case 'export_selected':
|
|
$content['nm']['selected'] = $selected;
|
|
$content['nm']['action'] = 'export';
|
|
break;
|
|
}
|
|
}
|
|
if ($content['nm']['action'])
|
|
{
|
|
if (!count($content['nm']['selected']) && !$content['nm']['select_all'])
|
|
{
|
|
$msg = lang('You need to select some entries first!');
|
|
}
|
|
else
|
|
{
|
|
// Action has an additional parameter
|
|
if(in_array($content['nm']['action'], array('owner', 'allowed')))
|
|
{
|
|
$action = $content['nm']['action'];
|
|
if($content['nm']['action'] == 'allowed')
|
|
{
|
|
$content['allowed'] = $content['allowed_private'] ? null : ($content['all_users'] ? 'all' : implode(',',$content['allowed']));
|
|
}
|
|
if(is_array($content[$content['nm']['action']]))
|
|
{
|
|
$content[$content['nm']['action']] = implode(',',$content[$content['nm']['action']]);
|
|
}
|
|
$content['nm']['action'] .= '_' . $content[$content['nm']['action']];
|
|
unset($content[$action]);
|
|
unset($content['all_users']);
|
|
unset($content['allowed_private']);
|
|
}
|
|
if ($this->action($content['nm']['action'],$content['nm']['selected'],$content['nm']['select_all'],
|
|
$success,$failed,$action_msg,'index',$msg))
|
|
{
|
|
$msg .= lang('%1 definition(s) %2',$success,$action_msg);
|
|
}
|
|
elseif(empty($msg))
|
|
{
|
|
$msg .= lang('%1 definition(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!is_array($content['nm'])) {
|
|
$content['nm'] = array(
|
|
'get_rows' => 'importexport.importexport_definitions_ui.get_rows',
|
|
'no_cat' => true,
|
|
'no_filter' => true,
|
|
'no_filter2' => true,
|
|
'header_right' => 'importexport.definition_index.add',
|
|
'csv_fields' => false, // Disable CSV export, uses own export
|
|
'default_cols' => '!actions', // switch legacy actions column and row off by default
|
|
'row_id' => 'definition_id',
|
|
);
|
|
if($_GET['application']) $content['nm']['col_filter']['application'] = $_GET['application'];
|
|
}
|
|
if(egw_session::appsession('index', 'importexport')) {
|
|
$content['nm'] = array_merge($content['nm'], egw_session::appsession('index', 'importexport'));
|
|
}
|
|
$content['nm']['actions'] = $this->get_actions();
|
|
$sel_options = array(
|
|
'type' => array(
|
|
'import' => lang('import'),
|
|
'export' => lang('export'),
|
|
),
|
|
'allowed_users' => array(null => lang('Private'), 'all' => lang('all'))
|
|
);
|
|
foreach ($this->plugins as $appname => $options)
|
|
{
|
|
if($GLOBALS['egw_info']['user']['apps'][$appname] || $GLOBALS['egw_info']['user']['apps']['admin']) {
|
|
$sel_options['application'][$appname] = lang($appname);
|
|
}
|
|
}
|
|
if($msg) $content['msg'] = $msg;
|
|
|
|
$etpl = new etemplate(self::_appname.'.definition_index');
|
|
return $etpl->exec( self::_appname.'.importexport_definitions_ui.index', $content, $sel_options, $readonlys, $preserv );
|
|
}
|
|
|
|
private function get_actions() {
|
|
$group = 0;
|
|
$actions = array(
|
|
'edit' => array(
|
|
'caption' => 'Open',
|
|
'default' => true,
|
|
'allowOnMultiple' => false,
|
|
'url' => 'menuaction=importexport.importexport_definitions_ui.edit&definition=$id',
|
|
'popup' => '500x500',
|
|
'group' => $group,
|
|
),
|
|
'add' => array(
|
|
'caption' => 'Add',
|
|
'url' => 'menuaction=importexport.importexport_definitions_ui.edit',
|
|
'popup' => '500x500',
|
|
'group' => $group,
|
|
),
|
|
'execute' => array(
|
|
'caption' => 'Execute',
|
|
'icon' => 'importexport/navbar',
|
|
'allowOnMultiple' => false,
|
|
'group' => $group,
|
|
),
|
|
'schedule' => array(
|
|
'caption' => 'Schedule',
|
|
'icon' => 'timesheet/navbar',
|
|
'allowOnMultiple' => false,
|
|
'url' => 'menuaction=importexport.importexport_schedule_ui.edit&definition=$id',
|
|
'popup' => '500x500',
|
|
'group' => $group,
|
|
),
|
|
'change' => array(
|
|
'caption' => 'Change',
|
|
'icon' => 'edit',
|
|
'children' => array(
|
|
'owner' => array(
|
|
'caption' => 'Owner',
|
|
'group' => 1,
|
|
'icon' => 'addressbook/accounts',
|
|
'nm_action' => 'open_popup',
|
|
),
|
|
'allowed' => array(
|
|
'caption' => 'Allowed users',
|
|
'group' => 1,
|
|
'icon' => 'addressbook/group',
|
|
'nm_action' => 'open_popup',
|
|
)
|
|
),
|
|
'disableClass' => 'rowNoEdit',
|
|
),
|
|
'select_all' => array(
|
|
'caption' => 'Whole query',
|
|
'checkbox' => true,
|
|
'hint' => 'Apply the action on the whole query, NOT only the shown definitions!!!',
|
|
'group' => ++$group,
|
|
),
|
|
'copy' => array(
|
|
'caption' => 'Copy',
|
|
'group' => ++$group,
|
|
),
|
|
'createexport' => array(
|
|
'caption' => 'Create export',
|
|
'hint' => 'Create a matching export definition based on this import definition',
|
|
'icon' => 'export',
|
|
'group' => $group,
|
|
'allowOnMultiple' => false,
|
|
'disableClass' => 'export'
|
|
),
|
|
|
|
'export' => array(
|
|
'caption' => 'Export',
|
|
'group' => $group,
|
|
'icon' => 'filesave'
|
|
),
|
|
'delete' => array(
|
|
'caption' => 'Delete',
|
|
'confirm' => 'Delete this entry',
|
|
'confirm_multiple' => 'Delete these entries',
|
|
'group' => ++$group,
|
|
'disableClass' => 'rowNoDelete',
|
|
),
|
|
);
|
|
|
|
// Unset admin actions
|
|
if(!$GLOBALS['egw_info']['user']['apps']['admin'])
|
|
{
|
|
unset($actions['schedule']);
|
|
}
|
|
return $actions;
|
|
}
|
|
|
|
/**
|
|
* apply an action to multiple entries
|
|
*
|
|
* @param string/int $action 'delete', 'export', etc.
|
|
* @param array $selected id's to use if !$use_all
|
|
* @param boolean $use_all if true use all entries of the current selection (in the session)
|
|
* @param int &$success number of succeded actions
|
|
* @param int &$failed number of failed actions (not enought permissions)
|
|
* @param string &$action_msg translated verb for the actions, to be used in a message like %1 entries 'deleted'
|
|
* @param string/array $session_name 'index' or 'email', or array with session-data depending if we are in the main list or the popup
|
|
* @return boolean true if all actions succeded, false otherwise
|
|
*/
|
|
function action($action,$selected,$use_all,&$success,&$failed,&$action_msg,$session_name,&$msg)
|
|
{
|
|
//echo __METHOD__."('$action', ".array2string($selected).', '.array2string($use_all).",,, '$session_name')";
|
|
if ($use_all)
|
|
{
|
|
// get the whole selection
|
|
$old_query = $query = is_array($session_name) ? $session_name : egw_session::appsession($session_name,'importexport');
|
|
|
|
@set_time_limit(0); // switch off the execution time limit, as it's for big selections to small
|
|
$query['num_rows'] = -1; // all
|
|
$query['csv_export'] = true; // so get_rows method _can_ produce different content or not store state in the session
|
|
$this->get_rows($query,$rows,$readonlys);
|
|
|
|
$selected = array();
|
|
foreach($rows as $row) {
|
|
$selected[] = $row['definition_id'];
|
|
}
|
|
if(!is_array($session_name))
|
|
{
|
|
// Restore old query
|
|
egw_session::appsession($session_name, 'importexport',$old_query);
|
|
}
|
|
}
|
|
|
|
// Dialogs to get options
|
|
list($action, $settings) = explode('_', $action, 2);
|
|
|
|
$bodefinitions = new importexport_definitions_bo(false, true);
|
|
|
|
switch($action) {
|
|
case 'execute':
|
|
// There's probably a way to do this in just JS, all the info should be there...
|
|
foreach($selected as $id) {
|
|
$definition = $bodefinitions->read((int)$id);
|
|
$link = egw::link('/index.php', array(
|
|
'menuaction' => 'importexport.importexport_'.$definition['type'].'_ui.'.$definition['type'].'_dialog',
|
|
'appname' => $definition['application'],
|
|
'definition' => $definition['name']
|
|
));
|
|
egw_framework::set_onload("egw_openWindowCentered2('$link','_blank',850,440,'yes');");
|
|
}
|
|
break;
|
|
case 'allowed':
|
|
$action = 'allowed_users';// Field is allowed_users, popup doesn't like _
|
|
case 'owner':
|
|
$action_msg = lang('changed'. ' ' . $action);
|
|
foreach($selected as $id) {
|
|
$definition = $bodefinitions->read((int)$id);
|
|
if($definition['definition_id']) {
|
|
// Prevent private with no owner
|
|
if(!$definition['owner'] && !$settings) $definition['owner'] = $GLOBALS['egw_info']['user']['account_id'];
|
|
|
|
$definition[$action] = $settings;
|
|
$bodefinitions->save($definition);
|
|
$success++;
|
|
}
|
|
}
|
|
break;
|
|
case 'delete':
|
|
$bodefinitions->delete($selected);
|
|
$action_msg = lang('deleted');
|
|
break;
|
|
|
|
case 'export' :
|
|
$action_msg = lang('exported');
|
|
$mime_type = ($GLOBALS['egw']->html->user_agent == 'msie' || $GLOBALS['egw']->html->user_agent == 'opera') ?
|
|
'application/octetstream' : 'application/octet-stream';
|
|
$name = 'importexport_definition.xml';
|
|
header('Content-Type: ' . $mime_type);
|
|
header('Content-Disposition: attachment; filename="'.$name.'"');
|
|
echo $bodefinitions->export($selected);
|
|
common::egw_exit();
|
|
break;
|
|
|
|
case 'copy':
|
|
$action_msg = lang('copied');
|
|
// Should only be one selected
|
|
foreach($selected as $id) {
|
|
$definition = $bodefinitions->read((int)$id);
|
|
if($definition['definition_id']) {
|
|
unset($definition['definition_id']);
|
|
$definition['name'] = $settings ? $settings : $definition['name'] . ' copy';
|
|
try {
|
|
$bodefinitions->save($definition);
|
|
} catch (Exception $e) {
|
|
try {
|
|
$definition['name'] .= ' ' . $GLOBALS['egw_info']['user']['account_lid'];
|
|
$bodefinitions->save($definition);
|
|
} catch (Exception $ex) {
|
|
$failed++;
|
|
$msg .= lang('Duplicate name, please choose another.');
|
|
continue;
|
|
}
|
|
}
|
|
$success++;
|
|
}
|
|
}
|
|
break;
|
|
case 'createexport':
|
|
$action_msg = lang('created');
|
|
// Should only be one selected
|
|
foreach($selected as $id) {
|
|
$definition = new importexport_definition($id);
|
|
try {
|
|
$export = $bodefinitions->export_from_import($definition);
|
|
$export->save();
|
|
} catch (Exception $e) {
|
|
if($export)
|
|
{
|
|
try {
|
|
$export->name = $export->name.' ' . $GLOBALS['egw_info']['user']['account_lid'];
|
|
$export->save();
|
|
} catch (Exception $ex) {
|
|
$failed++;
|
|
$msg .= lang('Duplicate name, please choose another.');
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$failed++;
|
|
}
|
|
}
|
|
$success++;
|
|
}
|
|
break;
|
|
}
|
|
return !$failed;
|
|
}
|
|
|
|
public function get_rows(&$query, &$rows, &$readonlys) {
|
|
$rows = array();
|
|
egw_session::appsession('index','importexport',$query);
|
|
$bodefinitions = new importexport_definitions_bo($query['col_filter'], true);
|
|
return $bodefinitions->get_rows($query, $rows, $readonlys);
|
|
}
|
|
|
|
/**
|
|
* Edit a definition
|
|
*
|
|
* To jump to a certain step, pass the previous step in the URL step=wizard_stepXX
|
|
* The wizard will validate that step, then display the _next_ step..
|
|
*/
|
|
function edit()
|
|
{
|
|
if(!$_definition = $_GET['definition'])
|
|
{
|
|
$content = array(
|
|
'edit' => true,
|
|
'application' => $_GET['application'],
|
|
'plugin' => $_GET['plugin']
|
|
);
|
|
|
|
// Jump to a step
|
|
if($_GET['step'])
|
|
{
|
|
$content['edit'] = false;
|
|
// Wizard will process previous step, then advance
|
|
$content['step'] = $this->get_step($_GET['step'],-1);
|
|
$content['button']['next'] = 'pressed';
|
|
$this->wizard($content);
|
|
}
|
|
else
|
|
{
|
|
// Initial form
|
|
$this->wizard($content);
|
|
}
|
|
return;
|
|
}
|
|
if(is_numeric($_GET['definition']))
|
|
{
|
|
$definition = (int)$_GET['definition'];
|
|
}
|
|
else
|
|
{
|
|
$definition = array('name' => $_definition);
|
|
}
|
|
$bodefinitions = new importexport_definitions_bo();
|
|
$definition = $bodefinitions->read($definition);
|
|
$definition['edit'] = true;
|
|
// Jump to a step
|
|
if($_GET['step'])
|
|
{
|
|
$definition['edit'] = false;
|
|
// Wizard will process previous step, then advance
|
|
$definition['step'] = $_GET['step'];;
|
|
$definition['button'] = array('next' => 'pressed');
|
|
}
|
|
$this->wizard($definition);
|
|
}
|
|
|
|
function wizard($content = null, $msg='')
|
|
{
|
|
$GLOBALS['egw_info']['flags']['java_script'] .=
|
|
"<script type='text/javascript'>
|
|
function xajax_eT_wrapper_init() {
|
|
//window.resizeTo(document.documentElement.scrollWidth+20,document.documentElement.offsetHeight+40);
|
|
window.moveTo(screen.availWidth/2 - window.outerWidth/2,
|
|
screen.availHeight/2 - window.outerHeight/2);
|
|
}
|
|
</script>";
|
|
|
|
$this->etpl->read('importexport.wizardbox');
|
|
$this->wizard_content_template =& $this->etpl->children[0]['data'][1]['A'][2][1]['name'];
|
|
|
|
if(is_array($content) &&! $content['edit'])
|
|
{
|
|
if(self::_debug) error_log('importexport.wizard->$content '. print_r($content,true));
|
|
// fetch plugin object
|
|
if($content['plugin'] && $content['application'])
|
|
{
|
|
$wizard_name = $content['application'] . '_wizard_' . str_replace($content['application'] . '_', '', $content['plugin']);
|
|
|
|
// we need to deal with the wizard object if exists
|
|
if (file_exists(EGW_SERVER_ROOT . '/'. $content['application'].'/importexport/class.wizard_'. $content['plugin'].'.inc.php'))
|
|
{
|
|
error_log('Deprecated location for importexport wizard. Please move it to app/inc/ and rename it to follow new conventions');
|
|
}
|
|
elseif (file_exists(EGW_SERVER_ROOT . '/'. $content['application']."/inc/class.$wizard_name.inc.php"))
|
|
{
|
|
$wizard_plugin = $wizard_name;
|
|
}
|
|
else
|
|
{
|
|
$wizard_plugin = $content['plugin'];
|
|
}
|
|
// App translations
|
|
if($content['application']) translation::add_app($content['application']);
|
|
|
|
$this->plugin = is_object($GLOBALS['egw']->$wizard_plugin) ? $GLOBALS['egw']->$wizard_plugin : new $wizard_plugin;
|
|
|
|
// Global object needs to be the same, or references to plugin don't work
|
|
if(!is_object($GLOBALS['egw']->importexport_definitions_ui) || $GLOBALS['egw']->importexport_definitions_ui !== $this)
|
|
$GLOBALS['egw']->importexport_definitions_ui =& $this;
|
|
}
|
|
// deal with buttons even if we are not on ajax
|
|
if(isset($content['button']) && array_search('pressed',$content['button']) === false && count($content['button']) == 1)
|
|
{
|
|
$button = array_keys($content['button']);
|
|
$content['button'] = array($button[0] => 'pressed');
|
|
}
|
|
|
|
// post process submitted step
|
|
if($content['step']) {
|
|
if(!$this->can_edit($content))
|
|
{
|
|
// Each step changes definition, reload it
|
|
$bodefinitions = new importexport_definitions_bo();
|
|
$definition = $bodefinitions->read($content);
|
|
$content = $definition + array('step' => $content['step'], 'button' => $content['button']);
|
|
}
|
|
if(!key_exists($content['step'],$this->steps))
|
|
{
|
|
$next_step = $this->plugin->$content['step']($content);
|
|
}
|
|
else
|
|
{
|
|
$next_step = $this->$content['step']($content);
|
|
}
|
|
} else {
|
|
die('Cannot find next step');
|
|
}
|
|
|
|
// pre precess next step
|
|
$sel_options = $readonlys = $preserv = array();
|
|
|
|
// Override next button on step 30, to do a regular submit for the file upload
|
|
if($next_step == 'wizard_step30')
|
|
{
|
|
$this->etpl->set_cell_attribute('button[next]', 'onclick', '');
|
|
}
|
|
|
|
// Disable finish button if required fields are missing
|
|
if(!$content['name'] || !$content['type'] || !$content['plugin']) {
|
|
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][finish]');");
|
|
}
|
|
if(!key_exists($next_step,$this->steps))
|
|
{
|
|
$this->wizard_content_template = $this->plugin->$next_step($content,$sel_options,$readonlys,$preserv);
|
|
}
|
|
else
|
|
{
|
|
$this->wizard_content_template = $this->$next_step($content,$sel_options,$readonlys,$preserv);
|
|
}
|
|
if(!$this->can_edit($content))
|
|
{
|
|
$readonlys[$this->wizard_content_template] = true;
|
|
$preserve = $content;
|
|
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][finish]');");
|
|
}
|
|
|
|
$html = $this->etpl->exec(self::_appname.'.importexport_definitions_ui.wizard',$content,$sel_options,$readonlys,$preserv,1);
|
|
}
|
|
else
|
|
{
|
|
// initial content
|
|
$GLOBALS['egw']->js->set_onload("xajax_eT_wrapper_init();");
|
|
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][previous]');");
|
|
|
|
$sel_options = $readonlys = $preserv = array();
|
|
if($content['edit'])
|
|
unset ($content['edit']);
|
|
|
|
$this->wizard_content_template = $this->wizard_step10($content, $sel_options, $readonlys, $preserv);
|
|
|
|
if(!$this->can_edit($content))
|
|
{
|
|
$readonlys[$this->wizard_content_template] = true;
|
|
$preserve = $content;
|
|
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][finish]');");
|
|
}
|
|
|
|
$html = $this->etpl->exec(self::_appname.'.importexport_definitions_ui.wizard',$content,$sel_options,$readonlys,$preserv,1);
|
|
}
|
|
|
|
if(class_exists('xajaxResponse'))
|
|
{
|
|
$this->response = new xajaxResponse();
|
|
|
|
egw_framework::include_css_js_response();
|
|
if ($content['closewindow'])
|
|
{
|
|
$this->response->addScript("opener.location.reload();");
|
|
$this->response->addScript("window.close();");
|
|
// If Browser can't close window we display a "close" buuton and
|
|
// need to disable normal buttons
|
|
$this->response->addAssign('exec[button][previous]','style.display', 'none');
|
|
$this->response->addAssign('exec[button][next]','style.display', 'none');
|
|
$this->response->addAssign('exec[button][finish]','style.display', 'none');
|
|
$this->response->addAssign('exec[button][cancel]','style.display', 'none');
|
|
}
|
|
$this->response->addAssign('contentbox', 'innerHTML', $html);
|
|
if (($onload = $GLOBALS['egw']->js->set_onload('')))
|
|
{
|
|
$this->response->addScript($onload);
|
|
}
|
|
$this->response->addAssign('picturebox', 'style.display', 'none');
|
|
$this->response->addScript("set_style_by_class('div','popupManual','display','inline');
|
|
popup_resize();
|
|
");
|
|
|
|
return $this->response->getXML();
|
|
}
|
|
else
|
|
{
|
|
$GLOBALS['egw']->js->set_onload("document.getElementById('picturebox').style.display = 'none';");
|
|
egw_framework::validate_file('.', 'etemplate', 'etemplate');
|
|
egw_framework::validate_file('.', 'etemplate', 'etemplate');
|
|
common::egw_header();
|
|
echo '<div id="divMain">'."\n";
|
|
echo '<div><h3>{Im|Ex}port Wizard</h3></div>';
|
|
// adding a manual icon to every popup
|
|
if ($GLOBALS['egw_info']['user']['apps']['manual'])
|
|
{
|
|
$manual = new etemplate('etemplate.popup.manual');
|
|
echo $manual->exec(self::_appname.'.importexport_definitions_ui.wizard',$content,$sel_options,$readonlys,$preserv,1);
|
|
unset($manual);
|
|
}
|
|
|
|
echo '<div id="contentbox">';
|
|
echo $html;
|
|
echo '</div></div>'."\n";
|
|
echo '<style type="text/css">#picturebox { position: absolute; right: 27px; top: 24px; }</style>'."\n";
|
|
echo '<div id="picturebox">'. $this->clock. '</div>';
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gets name of next step
|
|
*
|
|
* @param string $curr_step
|
|
* @param int $step_width
|
|
* @return string containing function name of next step
|
|
*/
|
|
function get_step ($curr_step, $step_width)
|
|
{
|
|
/*if($content['plugin'] && $content['application']&& !is_object($this->plugin))
|
|
{
|
|
$plugin_definition = $this->plugins[$content['application']][$content['plugin']]['definition'];
|
|
if($plugin_definition) $this->plugin = new $plugin_definition;
|
|
}*/
|
|
if(is_object($this->plugin) && is_array($this->plugin->steps))
|
|
{
|
|
$steps = array_merge($this->steps,$this->plugin->steps);
|
|
$steps = array_flip($steps); asort($steps); $steps = array_flip($steps);
|
|
}
|
|
else
|
|
{
|
|
$steps = $this->steps;
|
|
}
|
|
$step_keys = array_keys($steps);
|
|
$nn = array_search($curr_step,$step_keys)+(int)$step_width;
|
|
return (key_exists($nn,$step_keys)) ? $step_keys[$nn] : 'wizard_finish';
|
|
}
|
|
|
|
|
|
function wizard_step10(&$content, &$sel_options, &$readonlys, &$preserv)
|
|
{
|
|
if(self::_debug) error_log('importexport.importexport_definitions_ui::wizard_step10->$content '.print_r($content,true));
|
|
|
|
// return from step10
|
|
if ($content['step'] == 'wizard_step10')
|
|
{
|
|
switch (array_search('pressed', $content['button']))
|
|
{
|
|
case 'next':
|
|
return $this->get_step($content['step'],1);
|
|
case 'finish':
|
|
return 'wizard_finish';
|
|
default :
|
|
return $this->wizard_step10($content,$sel_options,$readonlys,$preserv);
|
|
}
|
|
|
|
}
|
|
// init step10
|
|
else
|
|
{
|
|
$content['msg'] = $this->steps['wizard_step10'];
|
|
foreach ($this->plugins as $appname => $options)
|
|
{
|
|
if($GLOBALS['egw_info']['user']['apps'][$appname] || $GLOBALS['egw_info']['user']['apps']['admin']) {
|
|
$sel_options['application'][$appname] = lang($appname);
|
|
}
|
|
}
|
|
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][previous]');");
|
|
$content['step'] = 'wizard_step10';
|
|
$preserv = $content;
|
|
unset ($preserv['button']);
|
|
return 'importexport.wizard_chooseapp';
|
|
}
|
|
|
|
}
|
|
|
|
// get plugin
|
|
function wizard_step20(&$content, &$sel_options, &$readonlys, &$preserv)
|
|
{
|
|
if(self::_debug) error_log('importexport.' . get_class($this) . '::wizard_step20->$content '.print_r($content,true));
|
|
|
|
// return from step20
|
|
if ($content['step'] == 'wizard_step20')
|
|
{
|
|
switch (array_search('pressed', $content['button']))
|
|
{
|
|
case 'next':
|
|
// There's no real reason the plugin has to come from any of these, as long as it has a $steps variable
|
|
if($this->plugin instanceof importexport_iface_import_plugin || $this->plugin instanceof importexport_wizard_basic_import_csv || strpos(get_class($this->plugin), 'import') !== false) {
|
|
$content['type'] = 'import';
|
|
} elseif($this->plugin instanceof importexport_iface_export_plugin || $this->plugin instanceof importexport_wizard_basic_export_csv || strpos(get_class($this->plugin),'export') !== false) {
|
|
$content['type'] = 'export';
|
|
} else {
|
|
throw new egw_exception('Invalid plugin');
|
|
}
|
|
return $this->get_step($content['step'],1);
|
|
case 'previous' :
|
|
unset ($content['plugin']);
|
|
if(is_object($this->response)) {
|
|
$this->response->addScript("disable_button('exec[button][previous]');");
|
|
}
|
|
return $this->get_step($content['step'],-1);
|
|
case 'finish':
|
|
return 'wizard_finish';
|
|
default :
|
|
return $this->wizard_step20($content,$sel_options,$readonlys,$preserv);
|
|
}
|
|
}
|
|
// init step20
|
|
else
|
|
{
|
|
$content['msg'] = $this->steps['wizard_step20'];
|
|
$config = config::read('phpgwapi');
|
|
foreach ($this->plugins[$content['application']] as $type => $plugins) {
|
|
if($config['export_limit'] == 'no' && !$GLOBALS['egw_info']['user']['apps']['admin'] && $type == 'export') continue;
|
|
foreach($plugins as $plugin => $name) {
|
|
$sel_options['plugin'][$plugin] = $name;
|
|
}
|
|
}
|
|
$content['step'] = 'wizard_step20';
|
|
$preserv = $content;
|
|
unset ($preserv['button']);
|
|
return 'importexport.wizard_chooseplugin';
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// name
|
|
function wizard_step21(&$content, &$sel_options, &$readonlys, &$preserv)
|
|
{
|
|
if(self::_debug) error_log('importexport.importexport_definitions_ui::wizard_step21->$content '.print_r($content,true));
|
|
|
|
// Check for duplicate name
|
|
$duplicate = isset($content['duplicate_error']);
|
|
if($content['name'] && !$duplicate)
|
|
{
|
|
try {
|
|
$check_definition = new importexport_definition($content['name']);
|
|
if($check_definition && $check_definition->definition_id && $check_definition->definition_id != $content['definition_id'])
|
|
{
|
|
throw new Exception('Already exists');
|
|
}
|
|
} catch (Exception $e) {
|
|
// throw new Exception('Already exists');
|
|
$content['duplicate_error'] = lang('Duplicate name, please choose another.');
|
|
|
|
// Try some suggestions
|
|
$suggestions = array(
|
|
$content['name'] .'-'. $GLOBALS['egw_info']['user']['account_lid'],
|
|
$content['name'] .'-'. $GLOBALS['egw_info']['user']['account_id'],
|
|
$content['name'] .'-'. egw_time::to('now', true),
|
|
//$content['name'] .'-'. rand(0,100),
|
|
);
|
|
foreach($suggestions as $key => $suggestion) {
|
|
$sug_definition = new importexport_definition($suggestion);
|
|
if($sug_definition->definition_id) {
|
|
unset($suggestions[$key]);
|
|
}
|
|
}
|
|
if($suggestions) {
|
|
$content['duplicate_error'] .= ' '. lang('Try')." \n" . implode("\n", $suggestions);
|
|
}
|
|
return $this->get_step($content['step'],0);
|
|
}
|
|
}
|
|
|
|
// return from step21
|
|
if ($content['step'] == 'wizard_step21' && !$duplicate)
|
|
{
|
|
switch (array_search('pressed', $content['button']))
|
|
{
|
|
case 'next':
|
|
return $this->get_step($content['step'],1);
|
|
case 'previous' :
|
|
return $this->get_step($content['step'],-1);
|
|
case 'finish':
|
|
return 'wizard_finish';
|
|
default :
|
|
return $this->wizard_step21($content,$sel_options,$readonlys,$preserv);
|
|
}
|
|
}
|
|
// init step21
|
|
else
|
|
{
|
|
$content['msg'] = $this->steps['wizard_step21'] . ($duplicate ? "\n".$content['duplicate_error'] : '');
|
|
$content['step'] = 'wizard_step21';
|
|
unset($content['duplicate_error']);
|
|
$preserv = $content;
|
|
unset ($preserv['button']);
|
|
return 'importexport.wizard_choosename';
|
|
}
|
|
}
|
|
|
|
// allowed users
|
|
function wizard_step90(&$content, &$sel_options, &$readonlys, &$preserv)
|
|
{
|
|
if(self::_debug) error_log('importexport.importexport_definitions_ui::wizard_step90->$content '.print_r($content,true));
|
|
|
|
// return from step90
|
|
if ($content['step'] == 'wizard_step90')
|
|
{
|
|
if($this->can_edit($content))
|
|
{
|
|
$content['owner'] = $content['just_me'] || !$GLOBALS['egw']->acl->check('share_definitions', EGW_ACL_READ,'importexport') ?
|
|
($content['owner'] ? $content['owner'] : $GLOBALS['egw_info']['user']['account_id']) :
|
|
null;
|
|
$content['allowed_users'] = $content['just_me'] ? '' : ($content['all_users'] ? 'all' : implode(',',$content['allowed_users']));
|
|
unset($content['just_me']);
|
|
}
|
|
|
|
// workaround for some ugly bug related to readonlys;
|
|
switch (array_search('pressed', $content['button']))
|
|
{
|
|
case 'previous' :
|
|
return $this->get_step($content['step'],-1);
|
|
case 'next':
|
|
case 'finish':
|
|
return 'wizard_finish';
|
|
default :
|
|
return $this->wizard_step90($content,$sel_options,$readonlys,$preserv);
|
|
}
|
|
}
|
|
// init step90
|
|
else
|
|
{
|
|
$content['msg'] = $this->steps['wizard_step90'];
|
|
$content['step'] = 'wizard_step90';
|
|
$preserv = $content;
|
|
|
|
// Set owner for non-admins
|
|
$content['just_me'] = ((!$content['allowed_users'] || !$content['allowed_users'][0] && count($content['allowed_users']) ==1) && $content['owner']);
|
|
//if(!$GLOBALS['egw_info']['user']['apps']['admin'] && !$GLOBALS['egw']->acl->check('share_definition', EGW_ACL_READ, 'importexport')) {
|
|
if(!$GLOBALS['egw']->acl->check('share_definition', EGW_ACL_READ, 'importexport') && !$GLOBALS['egw_info']['user']['apps']['admin']) {
|
|
$content['allowed_users'] = array();
|
|
$readonlys['allowed_users'] = true;
|
|
$readonlys['just_me'] = true;
|
|
$readonlys['all_users'] = true;
|
|
$content['just_me'] = true;
|
|
}
|
|
|
|
// Hide 'just me' checkbox, users get confused by read-only
|
|
if($readonlys['just_me'] || !$this->can_edit($content))
|
|
{
|
|
$content['no_just_me'] = true;
|
|
}
|
|
if($readonlys['all_users'] || !$this->can_edit($content))
|
|
{
|
|
$content['no_all_users'] = true;
|
|
}
|
|
unset ($preserv['button']);
|
|
$GLOBALS['egw']->js->set_onload("disable_button('exec[button][next]');");
|
|
if(is_object($this->response)) {
|
|
$this->response->addAssign('exec[button][next]','style.display', 'none');
|
|
}
|
|
return 'importexport.wizard_chooseallowedusers';
|
|
}
|
|
}
|
|
|
|
function wizard_finish(&$content)
|
|
{
|
|
if(self::_debug) error_log('importexport.importexport_definitions_ui::wizard_finish->$content '.print_r($content,true));
|
|
// Take out some UI leavings
|
|
unset($content['msg']);
|
|
unset($content['step']);
|
|
unset($content['button']);
|
|
|
|
$bodefinitions = new importexport_definitions_bo();
|
|
$bodefinitions->save($content);
|
|
// This message is displayed if browser cant close window
|
|
$content['msg'] = lang('ImportExport wizard finished successfully!');
|
|
$content['closewindow'] = true;
|
|
return 'importexport.wizard_close';
|
|
}
|
|
|
|
function import_definition($content='')
|
|
{
|
|
$bodefinitions = new importexport_definitions_bo();
|
|
if (is_array($content))
|
|
{
|
|
if($content['import_file']['tmp_name'])
|
|
{
|
|
$result = $bodefinitions->import($content['import_file']['tmp_name']);
|
|
$msg = lang('%1 definitions %2', count($result), lang('imported')) ."\n". implode("\n", array_keys($result));
|
|
return $this->index(null, $msg);
|
|
}
|
|
if($content['update'])
|
|
{
|
|
$applist = importexport_helper_functions::get_apps('all', true);
|
|
foreach($applist as $appname) {
|
|
importexport_helper_functions::load_defaults($appname);
|
|
}
|
|
return $this->index();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$etpl = new etemplate(self::_appname.'.import_definition');
|
|
return $etpl->exec(self::_appname.'.importexport_definitions_ui.import_definition',$content,array(),$readonlys,$preserv);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine if the user is allowed to edit the definition
|
|
*
|
|
*/
|
|
protected function can_edit(Array $definition)
|
|
{
|
|
if($definition['owner'] && $definition['owner'] == $GLOBALS['egw_info']['user']['account_id'])
|
|
{
|
|
// Definition belongs to user
|
|
return true;
|
|
}
|
|
elseif($definition['definition_id'] && !$definition['owner'] && $GLOBALS['egw_info']['user']['apps']['admin'])
|
|
{
|
|
// Definition is unowned, and user is an admin
|
|
return true;
|
|
}
|
|
elseif(!$definition['definition_id'])
|
|
{
|
|
// Definition is in-progress, not saved yet
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Site configuration
|
|
*/
|
|
public function site_config($content = array())
|
|
{
|
|
if(!$GLOBALS['egw_info']['user']['apps']['admin'])
|
|
{
|
|
egw::redirect_link('/home');
|
|
}
|
|
if($content['save'])
|
|
{
|
|
unset($content['save']);
|
|
|
|
// ACL
|
|
$GLOBALS['egw']->acl->delete_repository(self::_appname, 'definition',false);
|
|
$GLOBALS['egw']->acl->delete_repository(self::_appname, 'share_definition',false);
|
|
|
|
foreach($content['share_definition'] as $group)
|
|
{
|
|
$GLOBALS['egw']->acl->add_repository(self::_appname, 'share_definition', $group,EGW_ACL_READ);
|
|
}
|
|
unset($content['share_definition']);
|
|
|
|
// Other config
|
|
foreach($content as $key=>$value)
|
|
{
|
|
config::save_value($key, $value, 'importexport');
|
|
}
|
|
} elseif (isset($content['cancel'])) {
|
|
$GLOBALS['egw']->redirect_link('/admin/index.php');
|
|
}
|
|
|
|
$data = config::read(self::_appname);
|
|
$data['share_definition'] = $GLOBALS['egw']->acl->get_ids_for_location('share_definition', EGW_ACL_READ, self::_appname);
|
|
$sel_options['import_charsets'] = array_combine(mb_list_encodings(),mb_list_encodings());
|
|
|
|
// Remove 'standard' encodings to prevent doubles
|
|
foreach($GLOBALS['egw']->translation->get_installed_charsets() as $charset => $label)
|
|
{
|
|
unset($sel_options['import_charsets'][strtoupper($charset)]);
|
|
}
|
|
|
|
if(!$data['update']) $data['update'] = 'request';
|
|
|
|
$GLOBALS['egw_info']['flags']['app_header'] = lang('Site configuration') . ' - ' . lang(self::_appname);
|
|
$etpl = new etemplate(self::_appname.'.config');
|
|
$etpl->exec(self::_appname.'.importexport_definitions_ui.site_config',$data,$sel_options,$readonlys,$preserv);
|
|
}
|
|
}
|