From b1a6dd973220a31d81b0c51b0435ff58c6f9bf08 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 28 Sep 2010 22:45:57 +0000 Subject: [PATCH] Add basic support for importing users from CSV using admin_cmds --- .../inc/class.admin_import_users_csv.inc.php | 278 ++++++++++++++++++ ...lass.admin_wizard_import_users_csv.inc.php | 66 +++++ 2 files changed, 344 insertions(+) create mode 100644 admin/inc/class.admin_import_users_csv.inc.php create mode 100644 admin/inc/class.admin_wizard_import_users_csv.inc.php diff --git a/admin/inc/class.admin_import_users_csv.inc.php b/admin/inc/class.admin_import_users_csv.inc.php new file mode 100644 index 0000000000..fd08a9c7db --- /dev/null +++ b/admin/inc/class.admin_import_users_csv.inc.php @@ -0,0 +1,278 @@ + conversion) + 'field_mapping', // array( $csv_col_num => adb_filed) + 'conditions', /* => array containing condition arrays: + 'type' => exists, // exists + 'string' => '#kundennummer', + 'true' => array( + 'action' => update, + 'last' => true, + ), + 'false' => array( + 'action' => insert, + 'last' => true, + ),*/ + + ); + + /** + * actions which could be done to data entries + */ + protected static $actions = array( 'none', 'update', 'create', 'delete', 'disable', 'enable' ); + + /** + * conditions for actions + * + * @var array + */ + protected static $conditions = array( 'exists' ); + + /** + * @var definition + */ + private $definition; + + /** + * @var bool + */ + private $dry_run = false; + + /** + * @var bool is current user admin? + */ + private $is_admin = false; + + /** + * @var int + */ + private $user = null; + + /** + * List of import errors + */ + protected $errors = array(); + + /** + * List of actions, and how many times that action was taken + */ + protected $results = array(); + + /** + * imports entries according to given definition object. + * @param resource $_stream + * @param string $_charset + * @param definition $_definition + */ + public function import( $_stream, importexport_definition $_definition ) { + $import_csv = new importexport_import_csv( $_stream, array( + 'fieldsep' => $_definition->plugin_options['fieldsep'], + 'charset' => $_definition->plugin_options['charset'], + )); + + $this->definition = $_definition; + + // user, is admin ? + $this->is_admin = isset( $GLOBALS['egw_info']['user']['apps']['admin'] ) && $GLOBALS['egw_info']['user']['apps']['admin']; + $this->user = $GLOBALS['egw_info']['user']['account_id']; + + // dry run? + $this->dry_run = isset( $_definition->plugin_options['dry_run'] ) ? $_definition->plugin_options['dry_run'] : false; + + // set FieldMapping. + $import_csv->mapping = $_definition->plugin_options['field_mapping']; + + // set FieldConversion + $import_csv->conversion = $_definition->plugin_options['field_conversion']; + + //check if file has a header lines + if ( isset( $_definition->plugin_options['num_header_lines'] ) && $_definition->plugin_options['num_header_lines'] > 0) { + $import_csv->skip_records($_definition->plugin_options['num_header_lines']); + } elseif(isset($_definition->plugin_options['has_header_line']) && $_definition->plugin_options['has_header_line']) { + // First method is preferred + $import_csv->skip_records(1); + } + + // Start counting successes + $count = 0; + $this->results = array(); + + // Failures + $this->errors = array(); + + while ( $record = $import_csv->get_record() ) { + $success = false; + // don't import empty records + if( count( array_unique( $record ) ) < 2 ) continue; + + if ( $_definition->plugin_options['conditions'] ) { + foreach ( $_definition->plugin_options['conditions'] as $condition ) { + switch ( $condition['type'] ) { + // exists + case 'exists' : + $accounts = $GLOBALS['egw']->accounts->search(array( + 'type' => 'accounts', + 'query' => $record[$condition['string']], + 'query_type' => $condition['string'] + )); + if ( is_array( $accounts ) && count( $accounts ) >= 1 ) { + // apply action to all contacts matching this exists condition + $action = $condition['true']; + foreach ( (array)$accounts as $account ) { + $record['account_id'] = $account['account_id']; + $success = $this->action( $action['action'], $record, $import_csv->get_current_position() ); + } + } else { + $action = $condition['false']; + $success = ($this->action( $action['action'], $record, $import_csv->get_current_position() )); + } + break; + + // not supported action + default : + die('condition / action not supported!!!'); + break; + } + if ($action['last']) break; + } + } else { + // unconditional insert + $success = $this->action( 'insert', $record, $import_csv->get_current_position() ); + } + if($success) $count++; + } + return $count; + } + + /** + * perform the required action + * + * @param int $_action one of $this->actions + * @param array $_data contact data for the action + * @return bool success or not + */ + private function action ( $_action, $_data, $record_num = 0 ) { + switch ($_action) { + case 'none' : + return true; + case 'disable': + case 'enable': + $_data['account_expires'] = $_action == 'disable' ? 'already' : ''; + case 'update' : + case 'create' : + $command = new admin_cmd_edit_user($data['account_lid'], $_data); + if($this->dry_run) { + $this->results[$_action]++; + return true; + } + try { + $command->run(); + } catch (Exception $e) { + $this->errors[$record_num] = $e->getMessage(); + return false; + } + $this->results[$_action]++; + return true; + default: + throw new egw_exception('Unsupported action'); + + } + } + + /** + * returns translated name of plugin + * + * @return string name + */ + public static function get_name() { + return lang('User CSV import'); + } + + /** + * returns translated (user) description of plugin + * + * @return string descriprion + */ + public static function get_description() { + return lang("Creates / updates user accounts from CSV file"); + } + + /** + * retruns file suffix(s) plugin can handle (e.g. csv) + * + * @return string suffix (comma seperated) + */ + public static function get_filesuffix() { + return 'csv'; + } + + /** + * return etemplate components for options. + * @abstract We can't deal with etemplate objects here, as an uietemplate + * objects itself are scipt orientated and not "dialog objects" + * + * @return array ( + * name => string, + * content => array, + * sel_options => array, + * preserv => array, + * ) + */ + public function get_options_etpl() { + // lets do it! + } + + /** + * returns etemplate name for slectors of this plugin + * + * @return string etemplate name + */ + public function get_selectors_etpl() { + // lets do it! + } + + /** + * Returns errors that were encountered during importing + * Maximum of one error message per record, but you can append if you need to + * + * @return Array ( + * record_# => error message + * ) + */ + public function get_errors() { + return $this->errors; + } + + /** + * Returns a list of actions taken, and the number of records for that action. + * Actions are things like 'insert', 'update', 'delete', and may be different for each plugin. + * + * @return Array ( + * action => record count + * ) + */ + public function get_results() { + return $this->results; + } +} // end of iface_export_plugin +?> diff --git a/admin/inc/class.admin_wizard_import_users_csv.inc.php b/admin/inc/class.admin_wizard_import_users_csv.inc.php new file mode 100644 index 0000000000..fae4d4d3f2 --- /dev/null +++ b/admin/inc/class.admin_wizard_import_users_csv.inc.php @@ -0,0 +1,66 @@ + + * @version $Id: $ + */ + +class admin_wizard_import_users_csv extends importexport_wizard_basic_import_csv +{ + + /** + * constructor + */ + function __construct() + { + parent::__construct(); + + $this->steps += array( + 'wizard_step50' => lang('Manage mapping'), + ); + + // Field mapping + $this->mapping_fields = array( + 'account_lid' => lang('LoginID'), + 'account_firstname' => lang('First Name'), + 'account_lastname' => lang('Last Name'), + 'account_email' => lang('email'), + 'account_passwd' => lang('Password'), + 'account_passwd_2' => lang('Re-Enter Password'), + 'account_active' => lang('Account active'), + 'account_primary_group' => lang('primary Group'), + 'account_groups' => lang('Groups'), + 'account_expires' => lang('Expires'), + 'anonymous' => lang('Anonymous User (not shown in list sessions)'), + 'changepassword' => lang('Can change password'), + 'mustchangepassword' => lang('Must change password upon next login'), + ); + + // Actions + $this->actions = array( + 'none' => lang('none'), + 'update' => lang('update'), + 'create' => lang('create'), + 'delete' => lang('delete'), + 'disable' => lang('disable'), + 'enable' => lang('enable'), + ); + + // Conditions + $this->conditions = array( + 'exists' => lang('exists'), + ); + } + + function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv) + { + $result = parent::wizard_step50($content, $sel_options, $readonlys, $preserv); + $content['msg'] .= "\n*" ; + + return $result; + } +}