Open Monograph Press  3.3.0
UserXmlPKPUserFilter.inc.php
1 <?php
2 
16 import('lib.pkp.plugins.importexport.native.filter.NativeImportFilter');
17 
23  function __construct($filterGroup) {
24  $this->setDisplayName('User XML user import');
25  parent::__construct($filterGroup);
26  }
27 
28  //
29  // Implement template methods from NativeImportFilter
30  //
35  function getPluralElementName() {
36  return 'PKPUsers';
37  }
38 
39  //
40  // Implement template methods from PersistableFilter
41  //
45  function getClassName() {
46  return 'lib.pkp.plugins.importexport.users.filter.UserXmlPKPUserFilter';
47  }
48 
54  function parseUserGroup($node) {
55 
56  $filterDao = DAORegistry::getDAO('FilterDAO'); /* @var $filterDao FilterDAO */
57  $importFilters = $filterDao->getObjectsByGroup('user-xml=>usergroup');
58  assert(count($importFilters)==1); // Assert only a single unserialization filter
59  $importFilter = array_shift($importFilters);
60  $importFilter->setDeployment($this->getDeployment());
61  $userGroupDoc = new DOMDocument();
62  $userGroupDoc->appendChild($userGroupDoc->importNode($node, true));
63  return $importFilter->execute($userGroupDoc);
64  }
65 
71  function parseUser($node) {
72  $deployment = $this->getDeployment();
73  $context = $deployment->getContext();
74  $site = $deployment->getSite();
75 
76  // Create the data object
77  $userDao = DAORegistry::getDAO('UserDAO'); /* @var $userDao UserDAO */
78  $user = $userDao->newDataObject();
79 
80  // Password encryption
81  $encryption = null;
82 
83  // Handle metadata in subelements
84  for ($n = $node->firstChild; $n !== null; $n=$n->nextSibling) if (is_a($n, 'DOMElement')) switch($n->tagName) {
85  case 'username': $user->setUsername($n->textContent); break;
86  case 'givenname':
87  $locale = $n->getAttribute('locale');
88  if (empty($locale)) $locale = $site->getPrimaryLocale();
89  $user->setGivenName($n->textContent, $locale);
90  break;
91  case 'familyname':
92  $locale = $n->getAttribute('locale');
93  if (empty($locale)) $locale = $site->getPrimaryLocale();
94  $user->setFamilyName($n->textContent, $locale);
95  break;
96  case 'affiliation':
97  $locale = $n->getAttribute('locale');
98  if (empty($locale)) $locale = $site->getPrimaryLocale();
99  $user->setAffiliation($n->textContent, $locale);
100  break;
101  case 'country': $user->setCountry($n->textContent); break;
102  case 'email': $user->setEmail($n->textContent); break;
103  case 'url': $user->setUrl($n->textContent); break;
104  case 'orcid': $user->setOrcid($n->textContent); break;
105  case 'phone': $user->setPhone($n->textContent); break;
106  case 'billing_address': $user->setBillingAddress($n->textContent); break;
107  case 'mailing_address': $user->setMailingAddress($n->textContent); break;
108  case 'biography':
109  $locale = $n->getAttribute('locale');
110  if (empty($locale)) $locale = $site->getPrimaryLocale();
111  $user->setBiography($n->textContent, $locale);
112  break;
113  case 'gossip': $user->setGossip($n->textContent); break;
114  case 'signature':
115  $locale = $n->getAttribute('locale');
116  if (empty($locale)) $locale = $site->getPrimaryLocale();
117  $user->setSignature($n->textContent, $locale);
118  break;
119  case 'date_registered': $user->setDateRegistered($n->textContent); break;
120  case 'date_last_login': $user->setDateLastLogin($n->textContent); break;
121  case 'date_last_email': $user->setDateLastEmail($n->textContent); break;
122  case 'date_validated': $user->setDateValidated($n->textContent); break;
123  case 'inline_help':$n->textContent == 'true' ? $user->setInlineHelp(true) : $user->setInlineHelp(false) ; break;
124  case 'auth_id': $user->setAuthId($n->textContent); break;
125  case 'auth_string': $user->setAuthString($n->textContent); break;
126  case 'disabled_reason': $user->setDisabledReason($n->textContent); break;
127  case 'locales': $user->setLocales(preg_split('/:/', $n->textContent)); break;
128  case 'password':
129  if ($n->getAttribute('must_change') == 'true') {
130  $user->setMustChangePassword(true);
131  }
132 
133  if ($n->getAttribute('is_disabled') == 'true') {
134  $user->setDisabled(true);
135  }
136 
137  if ($n->getAttribute('encryption')) {
138  $encryption = $n->getAttribute('encryption');
139  }
140 
141  $passwordValueNodeList = $n->getElementsByTagNameNS($deployment->getNamespace(), 'value');
142  if ($passwordValueNodeList->length == 1) {
143  $password = $passwordValueNodeList->item(0);
144  $user->setPassword($password->textContent);
145  } else {
146  $this->addError(__('plugins.importexport.user.error.userHasNoPassword', array('username' => $user->getUsername())));
147  }
148 
149  break;
150  }
151 
152  // Password Import Validation
153  $password = $this->importUserPasswordValidation($user, $encryption);
154 
155  $userByUsername = $userDao->getByUsername($user->getUsername(), true);
156  $userByEmail = $userDao->getUserByEmail($user->getEmail(), true);
157  // username and email are both required and unique, so either
158  // both exist for one and the same user, or both do not exist
159  if ($userByUsername && $userByEmail && $userByUsername->getId() == $userByEmail->getId()) {
160  $user = $userByUsername;
161  $userId = $user->getId();
162  } elseif (!$userByUsername && !$userByEmail) {
163  // if user names do not exists in the site primary locale
164  // copy one of the existing for the default/required site primary locale
165  if (empty($user->getGivenName($site->getPrimaryLocale()))) {
166  // get all user given names, family names and affiliations
167  $userGivenNames = $user->getGivenName(null);
168  $userFamilyNames = $user->getFamilyName(null);
169  $userAffiliations = $user->getAffiliation(null);
170  // get just not empty user given names, family names and affiliations
171  $notEmptyGivenNames = $notEmptyFamilyNames = $notEmptyAffiliations = array();
172  $notEmptyGivenNames = array_filter($userGivenNames, function($a) {
173  return !empty($a);
174  });
175  // if all given names are empty, import fails
176  if (empty($notEmptyGivenNames)) {
177  fatalError("User given name is empty.");
178  }
179  if (!empty($userFamilyNames)) {
180  $notEmptyFamilyNames = array_filter($userFamilyNames, function($a) {
181  return !empty($a);
182  });
183  }
184  if (!empty($userAffiliations)) {
185  $notEmptyAffiliations = array_filter($userAffiliations, function($a) {
186  return !empty($a);
187  });
188  }
189  // see if both, given and family name, exist in the same locale
190  $commonLocales = array_intersect_key($notEmptyGivenNames, $notEmptyFamilyNames);
191  if (empty($commonLocales)) {
192  // if not: copy only the given name
193  $firstLocale = reset(array_keys($notEmptyGivenNames));
194  $user->setGivenName($notEmptyGivenNames[$firstLocale], $site->getPrimaryLocale());
195  } else {
196  // else: take the first common locale for given and family name
197  $firstLocale = reset(array_keys($commonLocales));
198  // see if there is affiliation in a common locale
199  $affiliationCommonLocales = array_intersect_key($notEmptyAffiliations, $commonLocales);
200  if (!empty($affiliationCommonLocales)) {
201  // take the first common locale to all, given name, family name and affiliation
202  $firstLocale = reset(array_keys($affiliationCommonLocales));
203  // copy affiliation
204  if (empty($notEmptyAffiliations[$site->getPrimaryLocale()])) {
205  $user->setAffiliation($notEmptyAffiliations[$firstLocale], $site->getPrimaryLocale());
206  }
207  }
208  //copy given and family name
209  $user->setGivenName($notEmptyGivenNames[$firstLocale], $site->getPrimaryLocale());
210  if (empty($notEmptyFamilyNames[$site->getPrimaryLocale()])) {
211  $user->setFamilyName($notEmptyFamilyNames[$firstLocale], $site->getPrimaryLocale());
212  }
213  }
214  }
215  $userId = $userDao->insertObject($user);
216 
217  // Insert reviewing interests, now that there is a userId.
218  $interestNodeList = $node->getElementsByTagNameNS($deployment->getNamespace(), 'review_interests');
219  if ($interestNodeList->length == 1) {
220  $n = $interestNodeList->item(0);
221  if ($n) {
222  $interests = preg_split('/,\s*/', $n->textContent);
223  import('lib.pkp.classes.user.InterestManager');
224  $interestManager = new InterestManager();
225  $interestManager->setInterestsForUser($user, $interests);
226  }
227  }
228 
229  // send USER_REGISTER e-mail only if it is a new inserted/registered user
230  // else, if the user already exists, its metadata will not be change (just groups will be re-assigned below)
231  if ($password) {
232  import('lib.pkp.classes.mail.MailTemplate');
233  $mail = new MailTemplate('USER_REGISTER');
234  $mail->setReplyTo($context->getSetting('contactEmail'), $context->getSetting('contactName'));
235  $mail->assignParams(array('username' => $user->getUsername(), 'password' => $password, 'userFullName' => $user->getFullName()));
236  $mail->addRecipient($user->getEmail(), $user->getFullName());
237  $mail->send();
238  }
239  } else {
240  // the username and the email do not match to the one and the same existing user
241  $this->addError(__('plugins.importexport.user.error.usernameEmailMismatch', array('username' => $user->getUsername(), 'email' => $user->getEmail())));
242  }
243 
244  // We can only assign a user to a user group if persisted to the database by $userId
245  if ($userId) {
246  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
247  $userGroupsFactory = $userGroupDao->getByContextId($context->getId());
248  $userGroups = $userGroupsFactory->toArray();
249 
250  // Extract user groups from the User XML and assign the user to those (existing) groups.
251  // Note: It is possible for a user to exist with no user group assignments so there is
252  // no fatalError() as is the case with PKPAuthor import.
253  $userGroupNodeList = $node->getElementsByTagNameNS($deployment->getNamespace(), 'user_group_ref');
254  if ($userGroupNodeList->length > 0) {
255  for ($i = 0 ; $i < $userGroupNodeList->length ; $i++) {
256  $n = $userGroupNodeList->item($i);
257  foreach ($userGroups as $userGroup) {
258  if (in_array($n->textContent, $userGroup->getName(null))) {
259  // Found a candidate; assign user to it.
260  $userGroupDao->assignUserToGroup($userId, $userGroup->getId());
261  }
262  }
263  }
264  }
265  }
266 
267  return $user;
268  }
269 
274  function handleElement($node) {
275  $deployment = $this->getDeployment();
276  $context = $deployment->getContext();
277 
278  for ($n = $node->firstChild; $n !== null; $n=$n->nextSibling) {
279  if (is_a($n, 'DOMElement')) {
280  $this->handleChildElement($n);
281  }
282  }
283 
284  }
285 
290  function handleChildElement($n) {
291  switch ($n->tagName) {
292  case 'user_group':
293  $this->parseUserGroup($n);
294  break;
295  case 'user':
296  $this->parseUser($n);
297  break;
298  default:
299  fatalError('Unknown element ' . $n->tagName);
300  }
301  }
302 
309  function importUserPasswordValidation($userToImport, $encryption) {
310  $passwordHash = $userToImport->getPassword();
311  $password = null;
312  if (!$encryption) {
313  $siteDao = DAORegistry::getDAO('SiteDAO'); /* @var $siteDao SiteDAO */
314  $site = $siteDao->getSite();
315  if (strlen($passwordHash) >= $site->getMinPasswordLength()) {
316  $userToImport->setPassword(Validation::encryptCredentials($userToImport->getUsername(), $passwordHash));
317  } else {
318  $this->addError(__('plugins.importexport.user.error.plainPasswordNotValid', array('username' => $userToImport->getUsername())));
319  }
320  } else {
321  if (password_needs_rehash($passwordHash, PASSWORD_BCRYPT)) {
322 
323  $password = Validation::generatePassword();
324  $userToImport->setPassword(Validation::encryptCredentials($userToImport->getUsername(), $password));
325 
326  $userToImport->setMustChangePassword(true);
327 
328  $this->addError(__('plugins.importexport.user.error.passwordHasBeenChanged', array('username' => $userToImport->getUsername())));
329  } else {
330  $userToImport->setPassword($passwordHash);
331  }
332  }
333 
334  return $password;
335  }
336 }
337 
338 
Validation\encryptCredentials
static encryptCredentials($username, $password, $encryption=false, $legacy=false)
Definition: Validation.inc.php:255
UserXmlPKPUserFilter\parseUserGroup
parseUserGroup($node)
Definition: UserXmlPKPUserFilter.inc.php:54
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
Filter\addError
addError($message)
Definition: Filter.inc.php:265
NativeImportExportFilter\getDeployment
getDeployment()
Definition: NativeImportExportFilter.inc.php:49
Validation\generatePassword
static generatePassword($length=null)
Definition: Validation.inc.php:283
UserXmlPKPUserFilter\importUserPasswordValidation
importUserPasswordValidation($userToImport, $encryption)
Definition: UserXmlPKPUserFilter.inc.php:309
MailTemplate
Subclass of Mail for mailing a template email.
Definition: MailTemplate.inc.php:21
UserXmlPKPUserFilter\handleChildElement
handleChildElement($n)
Definition: UserXmlPKPUserFilter.inc.php:290
NativeImportFilter
Base class that converts a Native XML document to a DataObject.
Definition: NativeImportFilter.inc.php:18
UserXmlPKPUserFilter\handleElement
handleElement($node)
Definition: UserXmlPKPUserFilter.inc.php:274
InterestManager
Handle user interest functions.
Definition: InterestManager.inc.php:16
UserXmlPKPUserFilter\parseUser
parseUser($node)
Definition: UserXmlPKPUserFilter.inc.php:71
UserXmlPKPUserFilter\getClassName
getClassName()
Definition: UserXmlPKPUserFilter.inc.php:45
UserXmlPKPUserFilter\getPluralElementName
getPluralElementName()
Definition: UserXmlPKPUserFilter.inc.php:35
fatalError
if(!function_exists('import')) fatalError($reason)
Definition: functions.inc.php:32
Filter\setDisplayName
setDisplayName($displayName)
Definition: Filter.inc.php:140
UserXmlPKPUserFilter
Base class that converts a User XML document to a set of users.
Definition: UserXmlPKPUserFilter.inc.php:18
UserXmlPKPUserFilter\__construct
__construct($filterGroup)
Definition: UserXmlPKPUserFilter.inc.php:23