* @license PHP License * @package WB * @subpackage content */ /** * Load required class */ WBClass::load('WBContent'); /** * Content component: User_Manager * * @version 1.5.0 * @package WB * @subpackage content */ class WBContent_User_Manager extends WBContent { /** * my parameter list * * * - feature: available feature "useradd" and "userimport" * @var array */ protected $config = array( 'action' => 'userlist', 'requiredgroup' => 'admin', 'goto' => '0', 'hideuser' => array(), 'orderfield' => 'surname', 'orderasc' => 1, 'searchfields' => array('nickname', 'forename', 'surname'), 'limit' => '-1', 'usefilter' => 0, 'feature' => array() ); /** * Current Mandator * @var WBMandator */ protected $mandator; /** * table * @var WBDatasource_Table */ protected $table; /** * user object * @var WBUser */ protected $patron; /** * relation table * @var WBDatasource_RelationTable */ private $relTable = null; /** * @var WBFormProcessor_Filter */ protected $filter; /** * CSV file to import users * @var WBFile_CSV */ private $csv; /** * current group id, if any * @var string */ private $gid = 0; /** * 2nd constructor */ protected function init() { parent::init(); $params = array( 'table' => WBClass::create('WBDatasource_Table') ); $this->table = $params['table']; $this->mandator = WBClass::create('WBMandator', $params); if (!$this->mandator->isEnabled()) { return; } } /** * run * * run component * * @return array parameter list */ public function run() { if (!$this->isUserInGroup($this->config['requiredgroup'])) { $this->loadTemplates('anon'); return $this->config; } $this->setupFeature(); // try to load user by id $this->patron = WBClass::create('WBUser'); if ($this->config['action'] != 'userlist' && 0 == strncmp($this->config['action'], 'user', 4)) { // check against mandator users if ($this->patron->load($this->req->get('user', 0))) { $this->tmpl->addGlobalVars($this->patron->getData()); } else { if (!in_array($this->config['action'], $this->config['feature'])) { $this->config['action'] = 'userlist'; } } // load group by id } else if ($this->config['action'] != 'grouplist' && strncmp($this->config['action'], 'group', 5) == 0) { $this->gid = $this->req->get('group', 0); $group = array(); if ($this->gid) { $group = $this->table->get('group', $this->gid); } if (1 == count($group)) { $group = $group[0]; } else { if ('groupadd' != $this->config['action']) { $this->config['action'] = 'grouplist'; } $this->gid = 0; $group = array(); } } $this->addConfigAsGlobalVars(); $this->tmpl->addGlobalVar('search_query', $this->req->get('searchquery', '')); $this->tmpl->addGlobalVar('search_query_url', urlencode($this->req->get('searchquery', ''))); $this->initFilter(); switch ($this->config['action']) { case 'groupadd': $group['id'] = '__new'; $this->tmpl->addGlobalVars($group); $this->initRelationTable('group'); $this->processForm('groupEdit', $group); break; case 'groupedit': $this->tmpl->addGlobalVars($group); $this->initRelationTable('group'); if ($this->relTable) { $this->relTable->inject($group); } $this->processForm('groupEdit', $group); break; case 'grouprm': // delete? $this->tmpl->addGlobalVars($group); if ($this->gid && $this->req->get('force', 'no') == 'yes') { $this->table->delete('group', $this->gid); $this->loadTemplates('groupRmDeleted'); break; } $this->loadTemplates('groupRm'); return $this->config; break; case 'grouplist': $this->loadTemplates('groupList'); break; case 'groupmember': if ($this->displayMemberList($group)) { return $this->config; } $this->loadTemplates('groupList'); break; case 'userimport': $list = $this->getFormElementList('userImport'); $this->processForm('userImport'); break; case 'useradd': $this->initRelationTable('user'); $data = array('id' => '__new'); $this->processForm('userEdit', $data); break; case 'useredit': $this->initRelationTable('user'); $data = $this->patron->getData(); $data['groups'] = array_keys($this->patron->getGroups()); if ($this->relTable) { $this->relTable->inject($data); } $this->processForm('userEdit', $data); break; case 'userpassword': $this->initRelationTable('user'); $data = $this->patron->getData(); $this->processForm('userPassword', $data); break; case 'userrm': $this->tmpl->addGlobalVars($this->patron->getData()); if ($this->req->get('force', 'no') == 'yes') { $this->table->delete('user', $this->patron->getId()); $this->loadTemplates('userRmDeleted'); break; } $this->loadTemplates('userRm'); break; case 'userdisplay': $this->tmpl->addGlobalVars($this->patron->getData()); $this->loadTemplates('userDisplay'); break; case 'userlist': default: $this->loadTemplates('userList'); break; } $this->displayUserList(); $this->displayGroupList(); return $this->config; } /** * Normalize List of Features * * Check $this-config['feature'] parameter againste list of known features: * - useradd * - userimport * * Set enabled features as global template vars "FEATURE_x" * @see $config */ private function setupFeature() { if (empty($this->config['feature'])) { return; } if (!is_array($this->config['feature'])) { $this->config['feature'] = array($this->config['feature']); } $feature = array(); foreach ($this->config['feature'] as $f) { switch ($f) { case 'useradd': case 'userimport': $feature[] = $f; $this->tmpl->addGlobalVar('feature_' . $f, 1); break; default: break; } } $this->config['feature'] = $feature; } /** * display list of records in table * * In case there is a template named "list_entry", it will be filled with paged * rows of table */ protected function displayGroupList() { if (!$this->tmpl->exists('group_list_entry')) { return; } $options = array( 'limit' => 25 ); if ($this->config['limit'] && intval($this->config['limit']) > 0) { $options['limit'] = intval($this->config['limit']); } $clause = array(); $pager = $this->table->getPager($this->part . __CLASS__ . 'group', 'group', null, $clause, $options); $this->tmpl->addGlobalVars($pager->browse($this->config['goto']), 'pager_'); $this->tmpl->addRows('group_list_entry', $pager->get()); } /** * Initialize Filter, if configured * */ protected function initFilter() { $this->filter = WBClass::create('WBFormProcessor_Filter'); $this->filter->setRequest($this->req); $this->filter->setTemplate($this->tmpl, $this->config['tmplDir']); if ($this->config['usefilter']) { $this->filter->setFormConfigDir($this->getFormConfigDir(), 'snippet'); } $this->filter->buildClause($this->config['searchfields']); } /** * display list of records in table * * In case there is a template named "list_entry", it will be filled with paged * rows of table */ protected function displayUserList() { if (!$this->tmpl->exists('user_list_entry')) { return; } $clause = $this->filter->getClause(); $options = $this->filter->getOptions(); if (!empty($this->config['hideuser']) && is_array($this->config['hideuser'])) { $clause[] = array( 'field' => $this->table->getIdentifier('user'), 'relation' => 'not_in', 'value' => $this->config['hideuser'] ); } // hide mandatory system users: mandator-* $clause[] = array( 'field' => 'nickname', 'relation' => 'not_begin', 'value' => 'mandator-' ); // hide all users of other mandators if ($this->mandator->isEnabled() && 0 != $this->mandator->getId()) { } // $this->addSearchQuery($clause); if ($this->config['limit'] && intval($this->config['limit']) > 0) { $options['limit'] = intval($this->config['limit']); } // order by if (!empty($this->config['orderfield'])) { $options['order'] = array( 'field' => $this->config['orderfield'], 'asc' => $this->config['orderasc'] ); } $pager = $this->table->getPager($this->part . __CLASS__ . 'user', 'user', null, $clause, $options); $this->tmpl->addGlobalVars($pager->browse($this->config['goto']), 'pager_'); $this->tmpl->addRows('user_list_entry', $pager->get()); } /** * Display Members * * @param array $group * @return bool true if group data is valid */ private function displayMemberList($group) { if (empty($group)) { return false; } $clause = array(); if (!empty($this->config['hideuser']) && is_array($this->config['hideuser'])) { $clause[] = array( 'field' => $this->table->getIdentifier('user'), 'relation' => 'not_in', 'value' => $this->config['hideuser'] ); } $clause[] = array( 'table' => 'usergroup', 'field' => $this->table->getIdentifier('group'), 'value' => $this->gid ); $options = array(); $options['join'] = array(); $options['join'][] = array( 'table' => 'usergroup', 'using' => $this->table->getIdentifier('user') ); if ($this->config['limit'] && intval($this->config['limit']) > 0) { $options['limit'] = intval($this->config['limit']); } // order by if (!empty($this->config['orderfield'])) { $options['order'] = array( 'field' => $this->config['orderfield'], 'asc' => $this->config['orderasc'] ); } $this->loadTemplates('memberList'); $this->tmpl->addGlobalVars($group, 'GROUP_'); $pager = $this->table->getPager($this->part . __CLASS__ . 'member', 'user', null, $clause, $options); $this->tmpl->addGlobalVars($pager->browse($this->config['goto']), 'pager_'); $this->tmpl->addRows('user_list_entry', $pager->get()); return true; } /** * Import users from CSV file * * @param patForms $form * @param array $values */ protected function onUserImportValid($form, $values) { $this->csv = WBClass::create('WBFile_CSV'); $els = $this->getFormElementList('userImport'); $dir = substr($els['file']['attributes']['uploaddir'], strlen(WBParam::get('wb/dir/base'))); if (!$this->csv->exists($dir . '/' . $values['file'])) { $this->tmpl->addGlobalVar('error', patI18n::dgettext('wombat', 'CSV File not found!')); return true; } $this->csv->open(); if (!$this->csv->guessFormat()) { $this->tmpl->addGlobalVar('error', patI18n::dgettext('wombat', 'CSV file corrupt or format unknown.')); } // need headline $line = $this->csv->read(); // lowercase for ($i = 0; $i < count($line); ++$i) { $line[$i] = strtolower(trim($line[$i])); } // check required columns $required = $this->user->getFieldsRequired(); $errors = array(); foreach ($required as $f) { if ('password' == $f) { continue; } if (!in_array($f, $line)) { $errors[] = WBString::populate(patI18n::dgettext('wombat','CSV file requires column named "{FIELD}"!'), array('field' => $f)); } } $this->tmpl->addGlobalVar('error_count', count($errors)); if (0 < count($errors)) { $this->tmpl->addVar('error_list', 'error', $errors); return true; } $this->csv->setMap(array_flip($line)); $storage = $this->user->getStorageModule(); $editable = $this->user->getFieldsEditable(); $editable = array_merge($editable, $required); $errors = array(); $import = array(); $row = 1; while (!$this->csv->eof()) { $ok = true; $line = $this->csv->read(); if (empty($line)) { continue; } $line = array_merge($line, $values); ++$row; // don't save the password, never ever if (isset($line['password'])) { unset($line['password']); } $save = array( 'approved' => 1, 'enabled' => 1 ); // check all required fields foreach ($required as $f) { if (!isset($line[$f]) || empty($line[$f])) { if ('password' == $f) { continue; } $ok = false; $msg = array( 'field' => $f, 'row' => $row ); $errors[] = WBString::populate(patI18n::dgettext('wombat','Required column "{FIELD}" is empty in line {ROW}!'), $msg); } } // editable fields foreach ($line as $k => $v) { if ('password' == $k) { continue; } // check editable if (!in_array($k, $editable)) { continue; } $save[$k] = trim($v); } if (!$ok) { continue; } $msg = array( 'row' => $row, 'email' => $line['email'], 'id' => null ); // check for existing user if (isset($save['nickname'])) { $check = array('nickname' => $save['nickname']); $msg['id'] = $storage->find($check); if (!empty($msg['id'])) { $ok = false; $import[] = WBString::populate(patI18n::dgettext('wombat','User account (id {ID}) for e-mail-address "{EMAIL}" already exists with nickname. (See line {ROW})'), $msg); } } if (isset($save['email'])) { $check = array('email' => $save['email']); $msg['id'] = $storage->find($check); if (!empty($msg['id'])) { $ok = false; $import[] = WBString::populate(patI18n::dgettext('wombat','User account (id {ID}) for e-mail address "{EMAIL}" already exists. (See line {ROW})'), $msg); } } if (!$ok) { continue; } $msg['id'] = $storage->set($save, true); $import[] = WBString::populate(patI18n::dgettext('wombat','Created user account (id {ID}) for e-mail address "{EMAIL}". (See line {ROW})'), $msg); $eData = $line; $eData['id'] = $msg['id']; WBEvent::trigger('user:imported', 'Created new user account {ID}', $eData); } $this->tmpl->addGlobalVar('error_count', count($errors)); if (0 < count($errors)) { $this->tmpl->addVar('error_list', 'error', $errors); } $this->tmpl->addGlobalVar('import_count', count($import)); if (0 < count($import)) { $this->tmpl->addVar('import_list', 'import', $import); } $this->csv->close(); $this->csv->unlink(); return true; } /** * Save user's primary data * * Update user's forename and surname * * @param patForms $form * @param array $values */ public function onUserPasswordValid($form, $values) { $this->tmpl->addGlobalVar('password_saved', 'not saved'); if (empty($values['password'])) { return true; } $save = array( 'password' => $values['password'] ); $this->patron->set($save); $this->tmpl->addGlobalVar('password_saved', 'saved'); $this->tmpl->addGlobalVar('password_plain', $values['password']); return true; } /** * Save user's primary data * * Update user's forename and surname * * @param patForms $form * @param array $values */ public function onUserEditValid($form, $values) { if ('useradd' == $this->config['action']) { $storage = $this->patron->getStorageModule(); $save = array( 'approved' => 1 ); $key = array( 'forename', 'surname', 'email', 'nickname' ); foreach ($key as $k) { if (isset($values[$k])) { $save[$k] = $values[$k]; } } $id = $storage->set($save, true); $this->patron->load($id); } // enable, disable user $doEnable = false; $enable = false; if (isset($values['enabled'])) { $doEnable = true; if ($values['enabled']) { $enable = true; } unset($values['enabled']); } if (isset($values['groups'])) { $this->patron->setGroups($values['groups']); } $this->patron->set($values); if ($this->relTable) { $this->relTable->extract($values); $this->relTable->delete($this->patron->getId()); $this->relTable->add($this->patron->getId()); } $this->tmpl->addGlobalVars($this->patron->getData()); // enable / disable if (!$doEnable) { return true; } if ($enable) { $this->patron->enable(); return true; } $this->patron->disable(); return true; } /** * Save group's primary data * * Update group data * * @param patForms $form * @param array $values */ public function onGroupEditValid($form, $values) { // don't save groupname by default if ('useredit' == $this->config['action']) { if (!isset($values['changegroupname']) || empty($values['changegroupname']) && isset($values['groupname'])) { unset($values['groupname']); } } if ($this->relTable) { $this->relTable->extract($values); if ('__new' != $this->gid) { $this->relTable->delete($this->gid); } } if (isset($values['changegroupname'])) { unset($values['changegroupname']); } unset($values['id']); unset($values[$this->table->getIdentifier('group')]); $this->gid = $this->table->save('group', $this->gid, $values); if ($this->relTable) { $this->relTable->add($this->gid); } $this->tmpl->addGlobalVar('id', $this->gid); return true; } /** * location of form config * * Return sub directory where form element definitions are located * * @return string folder */ protected function getFormConfigDir() { return 'user/manager'; } /** * Mangle Form Element List * * @param string name of the xml- and template-filename * @return array $elements */ protected function getFormElementList($name) { $elements = parent::getFormElementList($name); // only for user if ('userEdit' != $name) { return $elements; } // only for master mandator if (!$this->mandator->isEnabled() || 0 != $this->mandator->getId()) { return $elements; } $clause = array(); $option = array('limit' => 0); /* $optiom['join'] = array(); $optiom['join'][] = array(); */ $list = $this->table->get(WBDatasource::TABLE_MANDATOR, null, null, $clause, $option); $values = array(); foreach ($list as $l) { $values[] = array( 'value' => $l[$this->mandator->getIdentifier()], //'label' => sprintf('%s (%s, %s)', $l['customer'], $l['contactformname'], $l['contactsurname']) 'label' => sprintf('%s (%s)', $l['tradename'], $l['id']) ); } $clause = array(); $clause[] = array( 'field' => $this->table->getIdentifier(WBDatasource::TABLE_USER, true), 'value' => $this->patron->getId() ); $list = $this->table->get(WBDatasource::TABLE_MANDATORUSER, null, null, $clause, $option); $current = array(); foreach ($list as $l) { $current[] = $l[$this->mandator->getIdentifier()]; } $el = array( 'type' => 'SwitchGroup', 'attributes' => array( 'title' => 'Mandator', 'label' => 'Mandator', 'description' => 'Select mandators for users', 'class' => 'wb-multicol', 'required' => 'no', 'clicklabel' => 'yes', 'value' => $current, 'values' => $values ) ); $elements['mandatoruser'] = $el; return $elements; } /** * Add form rules to just created form * * @param patForms $form object * @param string name of the xml- and template-filename * @param array $elements list of elements current form * @return bool true on success */ protected function insertFormRules(&$form, $name, $elements) { return true; } /** * Add search criteria to clause * * See whether search options are set and add LIKE statements to clause. * Actually check in current request and configuration of search fields * * @param array $clause */ private function addSearchQuery(&$clause) { if (empty($this->config['searchfields'])) { return; } $query = trim($this->req->get('searchquery', '')); if (empty($query)) { return; } // normalize searchfields if (!is_array($this->config['searchfields'])) { $this->config['searchfields'] = array($this->config['searchfields']); } $query = array_map('trim', explode(' ', $query)); foreach ($query as $q) { if (strlen($q) < 3) { continue; } $c = array(); foreach ($this->config['searchfields'] as $f) { $c[] = array( 'field' => $f, 'relation' => 'like', 'value' => $q ); } $clause[] = array( 'type' => 'complex', 'bond' => 'or', 'clause' => $c ); } } /** * start up relation table object * * See whether relations are needed and start relations table * object if neccessary. * * @param string for group or user */ private function initRelationTable($type = 'user') { // load relation config $config = WBClass::create('WBConfig'); $config->load(sprintf('%s/%sEdit', $this->getFormConfigDir(), $type)); $conf = $config->get('relation', array()); if ($this->mandator->isEnabled() && 0 == $this->mandator->getId()) { if ('user' == $type) { $conf['mandatoruser'] = array( 'table' => WBDatasource::TABLE_MANDATORUSER, 'foreigntable' => WBDatasource::TABLE_MANDATOR ); } } if (empty($conf)) { return; } $this->relTable = WBClass::create('WBDatasource_RelationTable'); $this->relTable->setTable($this->table); $this->relTable->setConfig($type, $conf); } }