first commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/PKPUserImportExportDeployment.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class PKPUserImportExportDeployment
|
||||
*
|
||||
* @ingroup plugins_importexport_user
|
||||
*
|
||||
* @brief Class configuring the user import/export process to this
|
||||
* application's specifics.
|
||||
*/
|
||||
|
||||
namespace PKP\plugins\importexport\users;
|
||||
|
||||
use APP\core\Application;
|
||||
use PKP\context\Context;
|
||||
use PKP\plugins\importexport\PKPImportExportDeployment;
|
||||
use PKP\site\Site;
|
||||
use PKP\user\User;
|
||||
|
||||
class PKPUserImportExportDeployment extends PKPImportExportDeployment
|
||||
{
|
||||
/** @var Site */
|
||||
public $_site;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Context $context
|
||||
* @param ?User $user
|
||||
*/
|
||||
public function __construct($context, $user)
|
||||
{
|
||||
parent::__construct($context, $user);
|
||||
$site = Application::get()->getRequest()->getSite();
|
||||
$this->setSite($site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the site.
|
||||
*
|
||||
* @param Site $site
|
||||
*/
|
||||
public function setSite($site)
|
||||
{
|
||||
$this->_site = $site;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the site.
|
||||
*
|
||||
* @return Site
|
||||
*/
|
||||
public function getSite()
|
||||
{
|
||||
return $this->_site;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schema filename.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSchemaFilename()
|
||||
{
|
||||
return 'pkp-users.xsd';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the namespace URN
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return 'http://pkp.sfu.ca';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/PKPUserImportExportPlugin.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class PKPUserImportExportPlugin
|
||||
*
|
||||
* @ingroup plugins_importexport_users
|
||||
*
|
||||
* @brief User XML import/export plugin
|
||||
*/
|
||||
|
||||
namespace PKP\plugins\importexport\users;
|
||||
|
||||
use APP\facades\Repo;
|
||||
use APP\template\TemplateManager;
|
||||
use Exception;
|
||||
use PKP\context\Context;
|
||||
use PKP\core\JSONMessage;
|
||||
use PKP\core\PKPRequest;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\file\FileManager;
|
||||
use PKP\file\TemporaryFileDAO;
|
||||
use PKP\file\TemporaryFileManager;
|
||||
use PKP\filter\Filter;
|
||||
use PKP\filter\FilterDAO;
|
||||
use PKP\plugins\ImportExportPlugin;
|
||||
use PKP\user\User;
|
||||
|
||||
abstract class PKPUserImportExportPlugin extends ImportExportPlugin
|
||||
{
|
||||
/**
|
||||
* @copydoc Plugin::register()
|
||||
*
|
||||
* @param null|mixed $mainContextId
|
||||
*/
|
||||
public function register($category, $path, $mainContextId = null)
|
||||
{
|
||||
$success = parent::register($category, $path, $mainContextId);
|
||||
$this->addLocaleData();
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this plugin. The name must be unique within
|
||||
* its category.
|
||||
*
|
||||
* @return string name of plugin
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'UserImportExportPlugin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName()
|
||||
{
|
||||
return __('plugins.importexport.users.displayName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return __('plugins.importexport.users.description');
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc ImportExportPlugin::getPluginSettingsPrefix()
|
||||
*/
|
||||
public function getPluginSettingsPrefix()
|
||||
{
|
||||
return 'users';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the plugin.
|
||||
*
|
||||
* @param array $args
|
||||
* @param PKPRequest $request
|
||||
*/
|
||||
public function display($args, $request)
|
||||
{
|
||||
$templateMgr = TemplateManager::getManager($request);
|
||||
$context = $request->getContext();
|
||||
|
||||
parent::display($args, $request);
|
||||
|
||||
$templateMgr->assign('plugin', $this);
|
||||
|
||||
switch (array_shift($args)) {
|
||||
case 'index':
|
||||
case '':
|
||||
$templateMgr->display($this->getTemplateResource('index.tpl'));
|
||||
break;
|
||||
case 'uploadImportXML':
|
||||
$user = $request->getUser();
|
||||
$temporaryFileManager = new TemporaryFileManager();
|
||||
$temporaryFile = $temporaryFileManager->handleUpload('uploadedFile', $user->getId());
|
||||
if ($temporaryFile) {
|
||||
$json = new JSONMessage(true);
|
||||
$json->setAdditionalAttributes([
|
||||
'temporaryFileId' => $temporaryFile->getId()
|
||||
]);
|
||||
} else {
|
||||
$json = new JSONMessage(false, __('common.uploadFailed'));
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
return $json->getString();
|
||||
case 'importBounce':
|
||||
if (!$request->checkCSRF()) {
|
||||
throw new Exception('CSRF mismatch!');
|
||||
}
|
||||
$json = new JSONMessage(true);
|
||||
$json->setEvent('addTab', [
|
||||
'title' => __('plugins.importexport.users.results'),
|
||||
'url' => $request->url(null, null, null, ['plugin', $this->getName(), 'import'], ['temporaryFileId' => $request->getUserVar('temporaryFileId'), 'csrfToken' => $request->getSession()->getCSRFToken()]),
|
||||
]);
|
||||
header('Content-Type: application/json');
|
||||
return $json->getString();
|
||||
case 'import':
|
||||
if (!$request->checkCSRF()) {
|
||||
throw new Exception('CSRF mismatch!');
|
||||
}
|
||||
$temporaryFileId = $request->getUserVar('temporaryFileId');
|
||||
$temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /** @var TemporaryFileDAO $temporaryFileDao */
|
||||
$user = $request->getUser();
|
||||
$temporaryFile = $temporaryFileDao->getTemporaryFile($temporaryFileId, $user->getId());
|
||||
if (!$temporaryFile) {
|
||||
$json = new JSONMessage(true, __('plugins.importexport.users.uploadFile'));
|
||||
header('Content-Type: application/json');
|
||||
return $json->getString();
|
||||
}
|
||||
$temporaryFilePath = $temporaryFile->getFilePath();
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
$filter = $this->getUserImportExportFilter($context, $user);
|
||||
$users = $this->importUsers(file_get_contents($temporaryFilePath), $context, $user, $filter);
|
||||
$validationErrors = array_filter(libxml_get_errors(), function ($a) {
|
||||
return $a->level == LIBXML_ERR_ERROR || $a->level == LIBXML_ERR_FATAL;
|
||||
});
|
||||
$templateMgr->assign('validationErrors', $validationErrors);
|
||||
libxml_clear_errors();
|
||||
if ($filter->hasErrors()) {
|
||||
$templateMgr->assign('filterErrors', $filter->getErrors());
|
||||
}
|
||||
$templateMgr->assign('users', $users);
|
||||
$json = new JSONMessage(true, $templateMgr->fetch($this->getTemplateResource('results.tpl')));
|
||||
header('Content-Type: application/json');
|
||||
return $json->getString();
|
||||
case 'export':
|
||||
$filter = $this->getUserImportExportFilter($request->getContext(), $request->getUser(), false);
|
||||
|
||||
$exportXml = $this->exportUsers(
|
||||
(array) $request->getUserVar('selectedUsers'),
|
||||
$request->getContext(),
|
||||
$request->getUser(),
|
||||
$filter
|
||||
);
|
||||
$fileManager = new FileManager();
|
||||
$exportFileName = $this->getExportFileName($this->getExportPath(), 'users', $context, '.xml');
|
||||
$fileManager->writeFile($exportFileName, $exportXml);
|
||||
$fileManager->downloadByPath($exportFileName);
|
||||
$fileManager->deleteByPath($exportFileName);
|
||||
break;
|
||||
case 'exportAllUsers':
|
||||
$filter = $this->getUserImportExportFilter($request->getContext(), $request->getUser(), false);
|
||||
|
||||
$exportXml = $this->exportAllUsers(
|
||||
$request->getContext(),
|
||||
$request->getUser(),
|
||||
$filter
|
||||
);
|
||||
$fileManager = new FileManager();
|
||||
$exportFileName = $this->getExportFileName($this->getExportPath(), 'users', $context, '.xml');
|
||||
$fileManager->writeFile($exportFileName, $exportXml);
|
||||
$fileManager->downloadByPath($exportFileName);
|
||||
$fileManager->deleteByPath($exportFileName);
|
||||
break;
|
||||
default:
|
||||
$dispatcher = $request->getDispatcher();
|
||||
$dispatcher->handle404();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XML for all of users.
|
||||
*
|
||||
* @param Context $context
|
||||
* @param ?User $user
|
||||
* @param Filter $filter byRef parameter - import/export filter used
|
||||
*
|
||||
* @return string XML contents representing the supplied user IDs.
|
||||
*/
|
||||
public function exportAllUsers($context, $user, &$filter = null)
|
||||
{
|
||||
$users = Repo::user()->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
if (!$filter) {
|
||||
$filter = $this->getUserImportExportFilter($context, $user, false);
|
||||
}
|
||||
|
||||
return $this->exportUsers($users->toArray(), $context, $user, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XML for a set of users.
|
||||
*
|
||||
* @param array $ids mixed Array of users or user IDs
|
||||
* @param Context $context
|
||||
* @param ?User $user
|
||||
* @param Filter $filter byRef parameter - import/export filter used
|
||||
*
|
||||
* @return string XML contents representing the supplied user IDs.
|
||||
*/
|
||||
public function exportUsers($ids, $context, $user, &$filter = null)
|
||||
{
|
||||
$xml = '';
|
||||
|
||||
if (!$filter) {
|
||||
$filter = $this->getUserImportExportFilter($context, $user, false);
|
||||
}
|
||||
|
||||
$users = [];
|
||||
foreach ($ids as $id) {
|
||||
if ($id instanceof User) {
|
||||
$users[] = $id;
|
||||
} else {
|
||||
$user = Repo::user()->get($id, true);
|
||||
if ($user) {
|
||||
$users[] = $user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$userXml = $filter->execute($users);
|
||||
if ($userXml) {
|
||||
$xml = $userXml->saveXml();
|
||||
} else {
|
||||
fatalError('Could not convert users.');
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XML for a set of users.
|
||||
*
|
||||
* @param string $importXml XML contents to import
|
||||
* @param Context $context
|
||||
* @param ?User $user
|
||||
* @param Filter $filter byRef parameter - import/export filter used
|
||||
*
|
||||
* @return array Set of imported users
|
||||
*/
|
||||
public function importUsers($importXml, $context, $user, &$filter = null)
|
||||
{
|
||||
if (!$filter) {
|
||||
$filter = $this->getUserImportExportFilter($context, $user);
|
||||
}
|
||||
|
||||
return $filter->execute($importXml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return user filter for import purposes
|
||||
*
|
||||
* @param Context $context
|
||||
* @param ?User $user
|
||||
* @param bool $isImport return Import Filter if true - export if false
|
||||
*
|
||||
* @return Filter
|
||||
*/
|
||||
public function getUserImportExportFilter($context, $user, $isImport = true)
|
||||
{
|
||||
$filterDao = DAORegistry::getDAO('FilterDAO'); /** @var FilterDAO $filterDao */
|
||||
|
||||
if ($isImport) {
|
||||
$userFilters = $filterDao->getObjectsByGroup('user-xml=>user');
|
||||
} else {
|
||||
$userFilters = $filterDao->getObjectsByGroup('user=>user-xml');
|
||||
}
|
||||
|
||||
assert(count($userFilters) == 1); // Assert only a single unserialization filter
|
||||
$filter = array_shift($userFilters);
|
||||
$filter->setDeployment(new PKPUserImportExportDeployment($context, $user));
|
||||
|
||||
return $filter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/filter/NativeXmlUserGroupFilter.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class NativeXmlUserGroupFilter
|
||||
*
|
||||
* @ingroup plugins_importexport_users
|
||||
*
|
||||
* @brief Base class that converts a Native XML document to a set of user groups
|
||||
*/
|
||||
|
||||
namespace PKP\plugins\importexport\users\filter;
|
||||
|
||||
use APP\facades\Repo;
|
||||
use PKP\filter\FilterGroup;
|
||||
use PKP\userGroup\relationships\UserGroupStage;
|
||||
use PKP\userGroup\UserGroup;
|
||||
|
||||
class NativeXmlUserGroupFilter extends \PKP\plugins\importexport\native\filter\NativeImportFilter
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param FilterGroup $filterGroup
|
||||
*/
|
||||
public function __construct($filterGroup)
|
||||
{
|
||||
$this->setDisplayName('Native XML user group import');
|
||||
parent::__construct($filterGroup);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement template methods from NativeImportFilter
|
||||
//
|
||||
/**
|
||||
* Return the plural element name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPluralElementName()
|
||||
{
|
||||
return 'user_groups';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singular element name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSingularElementName()
|
||||
{
|
||||
return 'user_group';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a user_group element
|
||||
*
|
||||
* @param \DOMElement $node
|
||||
*
|
||||
* @return UserGroup Array of UserGroup objects
|
||||
*/
|
||||
public function handleElement($node)
|
||||
{
|
||||
$deployment = $this->getDeployment();
|
||||
$context = $deployment->getContext();
|
||||
|
||||
// Create the UserGroup object.
|
||||
$userGroup = Repo::userGroup()->newDataObject();
|
||||
$userGroup->setContextId($context->getId());
|
||||
|
||||
// Extract the name node element to see if this user group exists already.
|
||||
$nodeList = $node->getElementsByTagNameNS($deployment->getNamespace(), 'name');
|
||||
if ($nodeList->length > 0) {
|
||||
$content = $this->parseLocalizedContent($nodeList->item(0)); // $content[1] contains the localized name.
|
||||
$userGroups = Repo::userGroup()->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
foreach ($userGroups as $testGroup) {
|
||||
if (in_array($content[1], $testGroup->getName(null))) {
|
||||
return $testGroup; // we found one with the same name.
|
||||
}
|
||||
}
|
||||
|
||||
for ($n = $node->firstChild; $n !== null; $n = $n->nextSibling) {
|
||||
if ($n instanceof \DOMElement) {
|
||||
switch ($n->tagName) {
|
||||
case 'role_id': $userGroup->setRoleId($n->textContent);
|
||||
break;
|
||||
case 'is_default': $userGroup->setDefault($n->textContent ?? false);
|
||||
break;
|
||||
case 'show_title': $userGroup->setShowTitle($n->textContent ?? true);
|
||||
break;
|
||||
case 'name': $userGroup->setName($n->textContent, $n->getAttribute('locale'));
|
||||
break;
|
||||
case 'abbrev': $userGroup->setAbbrev($n->textContent, $n->getAttribute('locale'));
|
||||
break;
|
||||
case 'permit_self_registration': $userGroup->setPermitSelfRegistration($n->textContent ?? false);
|
||||
break;
|
||||
case 'permit_metadata_edit': $userGroup->setPermitMetadataEdit($n->textContent ?? false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$userGroupId = Repo::userGroup()->add($userGroup);
|
||||
|
||||
$stageNodeList = $node->getElementsByTagNameNS($deployment->getNamespace(), 'stage_assignments');
|
||||
if ($stageNodeList->length == 1) {
|
||||
$n = $stageNodeList->item(0);
|
||||
$assignedStages = preg_split('/:/', $n->textContent);
|
||||
foreach ($assignedStages as $stage) {
|
||||
if ($stage >= WORKFLOW_STAGE_ID_SUBMISSION && $stage <= WORKFLOW_STAGE_ID_PRODUCTION) {
|
||||
UserGroupStage::create([
|
||||
'contextId' => $context->getId(),
|
||||
'userGroupId' => $userGroupId,
|
||||
'stageId' => $stage
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $userGroup;
|
||||
} else {
|
||||
fatalError('unable to find "name" userGroup node element. Check import XML document structure for validity.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/filter/PKPUserUserXmlFilter.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class PKPUserUserXmlFilter
|
||||
*
|
||||
* @brief Base class that converts a set of users to a User XML document
|
||||
*/
|
||||
|
||||
namespace PKP\plugins\importexport\users\filter;
|
||||
|
||||
use APP\facades\Repo;
|
||||
use DOMDocument;
|
||||
use PKP\config\Config;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\filter\FilterDAO;
|
||||
use PKP\filter\FilterGroup;
|
||||
use PKP\plugins\importexport\native\filter\NativeExportFilter;
|
||||
use PKP\user\InterestManager;
|
||||
use PKP\user\User;
|
||||
|
||||
class PKPUserUserXmlFilter extends NativeExportFilter
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param FilterGroup $filterGroup
|
||||
*/
|
||||
public function __construct($filterGroup)
|
||||
{
|
||||
$this->setDisplayName('User XML user export');
|
||||
parent::__construct($filterGroup);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement template methods from Filter
|
||||
//
|
||||
/**
|
||||
* @see Filter::process()
|
||||
*
|
||||
* @param array $users Array of users
|
||||
*
|
||||
* @return DOMDocument
|
||||
*/
|
||||
public function &process(&$users)
|
||||
{
|
||||
// Create the XML document
|
||||
$doc = new DOMDocument('1.0', 'utf-8');
|
||||
$deployment = $this->getDeployment();
|
||||
|
||||
$rootNode = $doc->createElementNS($deployment->getNamespace(), 'PKPUsers');
|
||||
$this->addUserGroups($doc, $rootNode);
|
||||
|
||||
// Multiple users; wrap in a <users> element
|
||||
$usersNode = $doc->createElementNS($deployment->getNamespace(), 'users');
|
||||
foreach ($users as $user) {
|
||||
$usersNode->appendChild($this->createPKPUserNode($doc, $user));
|
||||
}
|
||||
$rootNode->appendChild($usersNode);
|
||||
$doc->appendChild($rootNode);
|
||||
$rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$rootNode->setAttribute('xsi:schemaLocation', $deployment->getNamespace() . ' ' . $deployment->getSchemaFilename());
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
//
|
||||
// \PKP\author\Author conversion functions
|
||||
//
|
||||
/**
|
||||
* Create and return a user node.
|
||||
*
|
||||
* @param DOMDocument $doc
|
||||
* @param User $user
|
||||
*
|
||||
* @return \DOMElement
|
||||
*/
|
||||
public function createPKPUserNode($doc, $user)
|
||||
{
|
||||
$deployment = $this->getDeployment();
|
||||
$context = $deployment->getContext();
|
||||
|
||||
// Create the user node
|
||||
$userNode = $doc->createElementNS($deployment->getNamespace(), 'user');
|
||||
|
||||
// Add metadata
|
||||
$this->createLocalizedNodes($doc, $userNode, 'givenname', $user->getGivenName(null));
|
||||
$this->createLocalizedNodes($doc, $userNode, 'familyname', $user->getFamilyName(null));
|
||||
$this->createLocalizedNodes($doc, $userNode, 'affiliation', $user->getAffiliation(null));
|
||||
|
||||
$this->createOptionalNode($doc, $userNode, 'country', $user->getCountry());
|
||||
$userNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'email', htmlspecialchars($user->getEmail(), ENT_COMPAT, 'UTF-8')));
|
||||
$this->createOptionalNode($doc, $userNode, 'url', $user->getUrl());
|
||||
$this->createOptionalNode($doc, $userNode, 'orcid', $user->getOrcid());
|
||||
if (is_array($user->getBiography(null))) {
|
||||
$this->createLocalizedNodes($doc, $userNode, 'biography', $user->getBiography(null));
|
||||
}
|
||||
|
||||
$userNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'username', htmlspecialchars($user->getUsername(), ENT_COMPAT, 'UTF-8')));
|
||||
|
||||
$this->createOptionalNode($doc, $userNode, 'gossip', $user->getGossip());
|
||||
|
||||
if (is_array($user->getSignature(null))) {
|
||||
$this->createLocalizedNodes($doc, $userNode, 'signature', $user->getSignature(null));
|
||||
}
|
||||
|
||||
$passwordNode = $doc->createElementNS($deployment->getNamespace(), 'password');
|
||||
$passwordNode->setAttribute('is_disabled', $user->getDisabled() ? 'true' : 'false');
|
||||
$passwordNode->setAttribute('must_change', $user->getMustChangePassword() ? 'true' : 'false');
|
||||
$passwordNode->setAttribute('encryption', Config::getVar('security', 'encryption'));
|
||||
$passwordNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'value', htmlspecialchars($user->getPassword(), ENT_COMPAT, 'UTF-8')));
|
||||
|
||||
$userNode->appendChild($passwordNode);
|
||||
|
||||
$this->createOptionalNode($doc, $userNode, 'date_registered', $user->getDateRegistered());
|
||||
$this->createOptionalNode($doc, $userNode, 'date_last_login', $user->getDateLastLogin());
|
||||
$this->createOptionalNode($doc, $userNode, 'date_last_email', $user->getDateLastEmail());
|
||||
$this->createOptionalNode($doc, $userNode, 'date_validated', $user->getDateValidated());
|
||||
$this->createOptionalNode($doc, $userNode, 'inline_help', $user->getInlineHelp() ? 'true' : 'false');
|
||||
$this->createOptionalNode($doc, $userNode, 'auth_string', $user->getAuthStr());
|
||||
$this->createOptionalNode($doc, $userNode, 'phone', $user->getPhone());
|
||||
$this->createOptionalNode($doc, $userNode, 'mailing_address', $user->getMailingAddress());
|
||||
$this->createOptionalNode($doc, $userNode, 'billing_address', $user->getBillingAddress());
|
||||
$this->createOptionalNode($doc, $userNode, 'locales', join(':', $user->getLocales()));
|
||||
if ($user->getDisabled()) {
|
||||
$this->createOptionalNode($doc, $userNode, 'disabled_reason', $user->getDisabledReason());
|
||||
}
|
||||
|
||||
$userGroups = Repo::userGroup()->getCollector()
|
||||
->filterByUserIds([$user->getId()])
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
foreach ($userGroups as $userGroup) {
|
||||
$userNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'user_group_ref', htmlspecialchars($userGroup->getName($context->getPrimaryLocale()), ENT_COMPAT, 'UTF-8')));
|
||||
}
|
||||
|
||||
// Add Reviewing Interests, if any.
|
||||
$interestManager = new InterestManager();
|
||||
$interests = $interestManager->getInterestsString($user);
|
||||
$this->createOptionalNode($doc, $userNode, 'review_interests', $interests);
|
||||
|
||||
return $userNode;
|
||||
}
|
||||
|
||||
public function addUserGroups($doc, $rootNode)
|
||||
{
|
||||
$deployment = $this->getDeployment();
|
||||
$context = $deployment->getContext();
|
||||
$userGroupsNode = $doc->createElementNS($deployment->getNamespace(), 'user_groups');
|
||||
|
||||
$userGroups = Repo::userGroup()->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
$filterDao = DAORegistry::getDAO('FilterDAO'); /** @var FilterDAO $filterDao */
|
||||
$userGroupExportFilters = $filterDao->getObjectsByGroup('usergroup=>user-xml');
|
||||
assert(count($userGroupExportFilters) == 1); // Assert only a single serialization filter
|
||||
$exportFilter = array_shift($userGroupExportFilters);
|
||||
$exportFilter->setDeployment($this->getDeployment());
|
||||
|
||||
$userGroupsArray = $userGroups->toArray();
|
||||
$userGroupsDoc = $exportFilter->execute($userGroupsArray);
|
||||
if ($userGroupsDoc->documentElement instanceof \DOMElement) {
|
||||
$clone = $doc->importNode($userGroupsDoc->documentElement, true);
|
||||
$rootNode->appendChild($clone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/filter/UserGroupNativeXmlFilter.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class UserGroupNativeXmlFilter
|
||||
*
|
||||
* @ingroup plugins_importexport_users
|
||||
*
|
||||
* @brief Base class that converts a set of user groups to a Native XML document
|
||||
*/
|
||||
|
||||
namespace PKP\plugins\importexport\users\filter;
|
||||
|
||||
use APP\facades\Repo;
|
||||
use DOMDocument;
|
||||
use PKP\filter\FilterGroup;
|
||||
use PKP\userGroup\UserGroup;
|
||||
|
||||
class UserGroupNativeXmlFilter extends \PKP\plugins\importexport\native\filter\NativeExportFilter
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param FilterGroup $filterGroup
|
||||
*/
|
||||
public function __construct($filterGroup)
|
||||
{
|
||||
$this->setDisplayName('Native XML user group export');
|
||||
parent::__construct($filterGroup);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement template methods from Filter
|
||||
//
|
||||
/**
|
||||
* @see Filter::process()
|
||||
*
|
||||
* @param array $userGroups Array of user groups
|
||||
*
|
||||
* @return DOMDocument
|
||||
*/
|
||||
public function &process(&$userGroups)
|
||||
{
|
||||
// Create the XML document
|
||||
$doc = new DOMDocument('1.0', 'utf-8');
|
||||
$deployment = $this->getDeployment();
|
||||
|
||||
// Multiple authors; wrap in a <authors> element
|
||||
$rootNode = $doc->createElementNS($deployment->getNamespace(), 'user_groups');
|
||||
foreach ($userGroups as $userGroup) {
|
||||
$rootNode->appendChild($this->createUserGroupNode($doc, $userGroup));
|
||||
}
|
||||
$doc->appendChild($rootNode);
|
||||
$rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$rootNode->setAttribute('xsi:schemaLocation', $deployment->getNamespace() . ' ' . $deployment->getSchemaFilename());
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
//
|
||||
// UserGroup conversion functions
|
||||
//
|
||||
/**
|
||||
* Create and return a user group node.
|
||||
*
|
||||
* @param DOMDocument $doc
|
||||
* @param UserGroup $userGroup
|
||||
*
|
||||
* @return \DOMElement
|
||||
*/
|
||||
public function createUserGroupNode($doc, $userGroup)
|
||||
{
|
||||
$deployment = $this->getDeployment();
|
||||
$context = $deployment->getContext();
|
||||
|
||||
// Create the user_group node
|
||||
$userGroupNode = $doc->createElementNS($deployment->getNamespace(), 'user_group');
|
||||
|
||||
// Add metadata
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'role_id', $userGroup->getRoleId()));
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'context_id', $userGroup->getContextId()));
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'is_default', $userGroup->getDefault() ? 'true' : 'false'));
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'show_title', $userGroup->getShowTitle() ? 'true' : 'false'));
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'permit_self_registration', $userGroup->getPermitSelfRegistration() ? 'true' : 'false'));
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'permit_metadata_edit', $userGroup->getPermitMetadataEdit() ? 'true' : 'false'));
|
||||
|
||||
$this->createLocalizedNodes($doc, $userGroupNode, 'name', $userGroup->getName(null));
|
||||
$this->createLocalizedNodes($doc, $userGroupNode, 'abbrev', $userGroup->getAbbrev(null));
|
||||
|
||||
$assignedStages = Repo::userGroup()->getAssignedStagesByUserGroupId($context->getId(), $userGroup->getId())->toArray();
|
||||
|
||||
$userGroupNode->appendChild($doc->createElementNS($deployment->getNamespace(), 'stage_assignments', htmlspecialchars(join(':', $assignedStages), ENT_COMPAT, 'UTF-8')));
|
||||
return $userGroupNode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/filter/UserXmlPKPUserFilter.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class UserXmlPKPUserFilter
|
||||
*
|
||||
* @ingroup plugins_importexport_users
|
||||
*
|
||||
* @brief Base class that converts a User XML document to a set of users
|
||||
*/
|
||||
|
||||
namespace PKP\plugins\importexport\users\filter;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\facades\Repo;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\filter\FilterDAO;
|
||||
use PKP\filter\FilterGroup;
|
||||
use PKP\mail\mailables\UserCreated;
|
||||
use PKP\plugins\importexport\users\PKPUserImportExportDeployment;
|
||||
use PKP\security\Validation;
|
||||
use PKP\site\SiteDAO;
|
||||
use PKP\user\InterestManager;
|
||||
use PKP\user\User;
|
||||
|
||||
class UserXmlPKPUserFilter extends \PKP\plugins\importexport\native\filter\NativeImportFilter
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param FilterGroup $filterGroup
|
||||
*/
|
||||
public function __construct($filterGroup)
|
||||
{
|
||||
$this->setDisplayName('User XML user import');
|
||||
parent::__construct($filterGroup);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement template methods from NativeImportFilter
|
||||
//
|
||||
/**
|
||||
* Return the plural element name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPluralElementName()
|
||||
{
|
||||
return 'PKPUsers';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a user_groups element
|
||||
*
|
||||
* @param \DOMElement $node
|
||||
*
|
||||
* @return array Array of UserGroup objects
|
||||
*/
|
||||
public function parseUserGroup($node)
|
||||
{
|
||||
$filterDao = DAORegistry::getDAO('FilterDAO'); /** @var FilterDAO $filterDao */
|
||||
$importFilters = $filterDao->getObjectsByGroup('user-xml=>usergroup');
|
||||
assert(count($importFilters) == 1); // Assert only a single unserialization filter
|
||||
$importFilter = array_shift($importFilters);
|
||||
$importFilter->setDeployment($this->getDeployment());
|
||||
$userGroupDoc = new \DOMDocument('1.0', 'utf-8');
|
||||
$userGroupDoc->appendChild($userGroupDoc->importNode($node, true));
|
||||
return $importFilter->execute($userGroupDoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a users element
|
||||
*
|
||||
* @param \DOMElement $node
|
||||
*
|
||||
* @return array Array of User objects
|
||||
*/
|
||||
public function parseUser($node)
|
||||
{
|
||||
/** @var PKPUserImportExportDeployment */
|
||||
$deployment = $this->getDeployment();
|
||||
$context = $deployment->getContext();
|
||||
$site = $deployment->getSite();
|
||||
|
||||
// Create the data object
|
||||
$user = Repo::user()->newDataObject();
|
||||
|
||||
// Password encryption
|
||||
$encryption = null;
|
||||
|
||||
// Handle metadata in subelements
|
||||
for ($n = $node->firstChild; $n !== null; $n = $n->nextSibling) {
|
||||
if ($n instanceof \DOMElement) {
|
||||
switch ($n->tagName) {
|
||||
case 'username': $user->setUsername($n->textContent);
|
||||
break;
|
||||
case 'givenname':
|
||||
$locale = $n->getAttribute('locale');
|
||||
if (empty($locale)) {
|
||||
$locale = $site->getPrimaryLocale();
|
||||
}
|
||||
$user->setGivenName($n->textContent, $locale);
|
||||
break;
|
||||
case 'familyname':
|
||||
$locale = $n->getAttribute('locale');
|
||||
if (empty($locale)) {
|
||||
$locale = $site->getPrimaryLocale();
|
||||
}
|
||||
$user->setFamilyName($n->textContent, $locale);
|
||||
break;
|
||||
case 'affiliation':
|
||||
$locale = $n->getAttribute('locale');
|
||||
if (empty($locale)) {
|
||||
$locale = $site->getPrimaryLocale();
|
||||
}
|
||||
$user->setAffiliation($n->textContent, $locale);
|
||||
break;
|
||||
case 'country': $user->setCountry($n->textContent);
|
||||
break;
|
||||
case 'email': $user->setEmail($n->textContent);
|
||||
break;
|
||||
case 'url': $user->setUrl($n->textContent);
|
||||
break;
|
||||
case 'orcid': $user->setOrcid($n->textContent);
|
||||
break;
|
||||
case 'phone': $user->setPhone($n->textContent);
|
||||
break;
|
||||
case 'billing_address': $user->setBillingAddress($n->textContent);
|
||||
break;
|
||||
case 'mailing_address': $user->setMailingAddress($n->textContent);
|
||||
break;
|
||||
case 'biography':
|
||||
$locale = $n->getAttribute('locale');
|
||||
if (empty($locale)) {
|
||||
$locale = $site->getPrimaryLocale();
|
||||
}
|
||||
$user->setBiography($n->textContent, $locale);
|
||||
break;
|
||||
case 'gossip': $user->setGossip($n->textContent);
|
||||
break;
|
||||
case 'signature':
|
||||
$locale = $n->getAttribute('locale');
|
||||
if (empty($locale)) {
|
||||
$locale = $site->getPrimaryLocale();
|
||||
}
|
||||
$user->setSignature($n->textContent, $locale);
|
||||
break;
|
||||
case 'date_registered': $user->setDateRegistered($n->textContent);
|
||||
break;
|
||||
case 'date_last_login': $user->setDateLastLogin($n->textContent);
|
||||
break;
|
||||
case 'date_last_email': $user->setDateLastEmail($n->textContent);
|
||||
break;
|
||||
case 'date_validated': $user->setDateValidated($n->textContent);
|
||||
break;
|
||||
case 'inline_help':$n->textContent == 'true' ? $user->setInlineHelp(true) : $user->setInlineHelp(false) ;
|
||||
break;
|
||||
case 'auth_string': $user->setAuthStr($n->textContent);
|
||||
break;
|
||||
case 'disabled_reason': $user->setDisabledReason($n->textContent);
|
||||
break;
|
||||
case 'locales': $user->setLocales(preg_split('/:/', $n->textContent));
|
||||
break;
|
||||
case 'password':
|
||||
if ($n->getAttribute('must_change') == 'true') {
|
||||
$user->setMustChangePassword(true);
|
||||
}
|
||||
|
||||
if ($n->getAttribute('is_disabled') == 'true') {
|
||||
$user->setDisabled(true);
|
||||
}
|
||||
|
||||
if ($n->getAttribute('encryption')) {
|
||||
$encryption = $n->getAttribute('encryption');
|
||||
}
|
||||
|
||||
$passwordValueNodeList = $n->getElementsByTagNameNS($deployment->getNamespace(), 'value');
|
||||
if ($passwordValueNodeList->length == 1) {
|
||||
$password = $passwordValueNodeList->item(0);
|
||||
$user->setPassword($password->textContent);
|
||||
} else {
|
||||
$this->addError(__('plugins.importexport.user.error.userHasNoPassword', ['username' => $user->getUsername()]));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Password Import Validation
|
||||
$password = $this->importUserPasswordValidation($user, $encryption);
|
||||
|
||||
$userByUsername = Repo::user()->getByUsername($user->getUsername(), true);
|
||||
$userByEmail = Repo::user()->getByEmail($user->getEmail(), true);
|
||||
// username and email are both required and unique, so either
|
||||
// both exist for one and the same user, or both do not exist
|
||||
if ($userByUsername && $userByEmail && $userByUsername->getId() == $userByEmail->getId()) {
|
||||
$user = $userByUsername;
|
||||
$userId = $user->getId();
|
||||
} elseif (!$userByUsername && !$userByEmail) {
|
||||
// if user names do not exists in the site primary locale
|
||||
// copy one of the existing for the default/required site primary locale
|
||||
if (empty($user->getGivenName($site->getPrimaryLocale()))) {
|
||||
// get all user given names, family names and affiliations
|
||||
$userGivenNames = $user->getGivenName(null);
|
||||
$userFamilyNames = $user->getFamilyName(null);
|
||||
$userAffiliations = $user->getAffiliation(null);
|
||||
// get just not empty user given names, family names and affiliations
|
||||
$notEmptyGivenNames = $notEmptyFamilyNames = $notEmptyAffiliations = [];
|
||||
$notEmptyGivenNames = array_filter($userGivenNames, function ($a) {
|
||||
return !empty($a);
|
||||
});
|
||||
// if all given names are empty, import fails
|
||||
if (empty($notEmptyGivenNames)) {
|
||||
fatalError('User given name is empty.');
|
||||
}
|
||||
if (!empty($userFamilyNames)) {
|
||||
$notEmptyFamilyNames = array_filter($userFamilyNames, function ($a) {
|
||||
return !empty($a);
|
||||
});
|
||||
}
|
||||
if (!empty($userAffiliations)) {
|
||||
$notEmptyAffiliations = array_filter($userAffiliations, function ($a) {
|
||||
return !empty($a);
|
||||
});
|
||||
}
|
||||
// see if both, given and family name, exist in the same locale
|
||||
$commonLocales = array_intersect_key($notEmptyGivenNames, $notEmptyFamilyNames);
|
||||
if (empty($commonLocales)) {
|
||||
// if not: copy only the given name
|
||||
$firstLocale = reset(array_keys($notEmptyGivenNames));
|
||||
$user->setGivenName($notEmptyGivenNames[$firstLocale], $site->getPrimaryLocale());
|
||||
} else {
|
||||
// else: take the first common locale for given and family name
|
||||
$firstLocale = reset(array_keys($commonLocales));
|
||||
// see if there is affiliation in a common locale
|
||||
$affiliationCommonLocales = array_intersect_key($notEmptyAffiliations, $commonLocales);
|
||||
if (!empty($affiliationCommonLocales)) {
|
||||
// take the first common locale to all, given name, family name and affiliation
|
||||
$firstLocale = reset(array_keys($affiliationCommonLocales));
|
||||
// copy affiliation
|
||||
if (empty($notEmptyAffiliations[$site->getPrimaryLocale()])) {
|
||||
$user->setAffiliation($notEmptyAffiliations[$firstLocale], $site->getPrimaryLocale());
|
||||
}
|
||||
}
|
||||
//copy given and family name
|
||||
$user->setGivenName($notEmptyGivenNames[$firstLocale], $site->getPrimaryLocale());
|
||||
if (empty($notEmptyFamilyNames[$site->getPrimaryLocale()])) {
|
||||
$user->setFamilyName($notEmptyFamilyNames[$firstLocale], $site->getPrimaryLocale());
|
||||
}
|
||||
}
|
||||
}
|
||||
$userId = Repo::user()->add($user);
|
||||
|
||||
// Insert reviewing interests, now that there is a userId.
|
||||
$interestNodeList = $node->getElementsByTagNameNS($deployment->getNamespace(), 'review_interests');
|
||||
if ($interestNodeList->length == 1) {
|
||||
$n = $interestNodeList->item(0);
|
||||
if ($n) {
|
||||
$interests = preg_split('/,\s*/', $n->textContent);
|
||||
$interestManager = new InterestManager();
|
||||
$interestManager->setInterestsForUser($user, $interests);
|
||||
}
|
||||
}
|
||||
|
||||
// send USER_REGISTER e-mail only if it is a new inserted/registered user
|
||||
// else, if the user already exists, its metadata will not be change (just groups will be re-assigned below)
|
||||
if ($password) {
|
||||
$template = Repo::emailTemplate()->getByKey($context->getId(), UserCreated::getEmailTemplateKey());
|
||||
$sender = Application::get()->getRequest()->getUser();
|
||||
$mailable = new UserCreated($context, $password);
|
||||
$mailable
|
||||
->recipients($user)
|
||||
->sender($sender)
|
||||
->replyTo($context->getData('contactEmail'), $context->getData('contactName'))
|
||||
->subject($template->getLocalizedData('subject'))
|
||||
->body($template->getLocalizedData('body'));
|
||||
|
||||
Mail::send($mailable);
|
||||
}
|
||||
} else {
|
||||
// the username and the email do not match to the one and the same existing user
|
||||
$this->addError(__('plugins.importexport.user.error.usernameEmailMismatch', ['username' => $user->getUsername(), 'email' => $user->getEmail()]));
|
||||
}
|
||||
|
||||
// We can only assign a user to a user group if persisted to the database by $userId
|
||||
if ($userId) {
|
||||
$userGroups = Repo::userGroup()->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getMany();
|
||||
|
||||
// Extract user groups from the User XML and assign the user to those (existing) groups.
|
||||
// Note: It is possible for a user to exist with no user group assignments so there is
|
||||
// no fatalError() as is the case with \PKP\author\Author import.
|
||||
$userGroupNodeList = $node->getElementsByTagNameNS($deployment->getNamespace(), 'user_group_ref');
|
||||
if ($userGroupNodeList->length > 0) {
|
||||
for ($i = 0 ; $i < $userGroupNodeList->length ; $i++) {
|
||||
$n = $userGroupNodeList->item($i);
|
||||
|
||||
/** @var \PKP\userGroup\UserGroup $userGroup */
|
||||
foreach ($userGroups as $userGroup) {
|
||||
// if the given user associated group name in within tag 'user_group_ref' is in the list of $userGroup name local list
|
||||
// and the user is not already assigned to that group
|
||||
if (in_array($n->textContent, $userGroup->getName(null)) && !Repo::userGroup()->userInGroup($userId, $userGroup->getId())) {
|
||||
// Found a candidate; assign user to it.
|
||||
Repo::userGroup()->assignUserToGroup($userId, $userGroup->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a singular element import.
|
||||
*
|
||||
* @param \DOMElement $node
|
||||
*/
|
||||
public function handleElement($node)
|
||||
{
|
||||
$deployment = $this->getDeployment();
|
||||
$context = $deployment->getContext();
|
||||
|
||||
for ($n = $node->firstChild; $n !== null; $n = $n->nextSibling) {
|
||||
if ($n instanceof \DOMElement) {
|
||||
$this->handleChildElement($n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an element whose parent is the submission element.
|
||||
*
|
||||
* @param \DOMElement $n
|
||||
*/
|
||||
public function handleChildElement($n)
|
||||
{
|
||||
switch ($n->tagName) {
|
||||
case 'user_group':
|
||||
$this->parseUserGroup($n);
|
||||
break;
|
||||
case 'user':
|
||||
$this->parseUser($n);
|
||||
break;
|
||||
default:
|
||||
fatalError('Unknown element ' . $n->tagName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation process for imported passwords
|
||||
*
|
||||
* @param User $userToImport ByRef. The user that is being imported.
|
||||
* @param string $encryption null, sha1, md5 (or any other encryption algorithm defined)
|
||||
*
|
||||
* @return string if a new password is generated, the function returns it.
|
||||
*/
|
||||
public function importUserPasswordValidation($userToImport, $encryption)
|
||||
{
|
||||
$passwordHash = $userToImport->getPassword();
|
||||
$password = null;
|
||||
if (!$encryption) {
|
||||
$siteDao = DAORegistry::getDAO('SiteDAO'); /** @var SiteDAO $siteDao */
|
||||
$site = $siteDao->getSite();
|
||||
if (strlen($passwordHash) >= $site->getMinPasswordLength()) {
|
||||
$userToImport->setPassword(Validation::encryptCredentials($userToImport->getUsername(), $passwordHash));
|
||||
} else {
|
||||
$this->addError(__('plugins.importexport.user.error.plainPasswordNotValid', ['username' => $userToImport->getUsername()]));
|
||||
}
|
||||
} else {
|
||||
if (password_needs_rehash($passwordHash, PASSWORD_BCRYPT)) {
|
||||
$password = Validation::generatePassword();
|
||||
$userToImport->setPassword(Validation::encryptCredentials($userToImport->getUsername(), $password));
|
||||
|
||||
$userToImport->setMustChangePassword(true);
|
||||
|
||||
$this->addError(__('plugins.importexport.user.error.passwordHasBeenChanged', ['username' => $userToImport->getUsername()]));
|
||||
} else {
|
||||
$userToImport->setPassword($passwordHash);
|
||||
}
|
||||
}
|
||||
|
||||
return $password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE filterConfig SYSTEM "../../../../dtd/filterConfig.dtd">
|
||||
|
||||
<!--
|
||||
* filterConfig.xml
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* Filter Configuration.
|
||||
-->
|
||||
<filterConfig>
|
||||
<filterGroups>
|
||||
<filterGroup
|
||||
symbolic="user=>user-xml"
|
||||
displayName="plugins.importexport.users.displayName"
|
||||
description="plugins.importexport.users.description"
|
||||
inputType="class::lib.pkp.classes.user.User[]"
|
||||
outputType="xml::schema(lib/pkp/plugins/importexport/users/pkp-users.xsd)" />
|
||||
<!-- Native XML Users input -->
|
||||
<filterGroup
|
||||
symbolic="user-xml=>user"
|
||||
displayName="plugins.importexport.users.displayName"
|
||||
description="plugins.importexport.users.description"
|
||||
inputType="xml::schema(lib/pkp/plugins/importexport/users/pkp-users.xsd)"
|
||||
outputType="class::classes.users.User[]" />
|
||||
<!-- Native XML usergroup output -->
|
||||
<filterGroup
|
||||
symbolic="usergroup=>user-xml"
|
||||
displayName="plugins.importexport.users.displayName"
|
||||
description="plugins.importexport.users.description"
|
||||
inputType="class::lib.pkp.classes.security.UserGroup[]"
|
||||
outputType="xml::schema(lib/pkp/plugins/importexport/users/pkp-users.xsd)" />
|
||||
<!-- Native XML usergroup input -->
|
||||
<filterGroup
|
||||
symbolic="user-xml=>usergroup"
|
||||
displayName="plugins.importexport.native.displayName"
|
||||
description="plugins.importexport.native.description"
|
||||
inputType="xml::schema(lib/pkp/plugins/importexport/users/pkp-users.xsd)"
|
||||
outputType="class::lib.pkp.classes.security.UserGroup[]" />
|
||||
</filterGroups>
|
||||
<filters>
|
||||
<!-- Native XML users output -->
|
||||
<filter
|
||||
inGroup="user=>user-xml"
|
||||
class="PKP\plugins\importexport\users\filter\PKPUserUserXmlFilter"
|
||||
isTemplate="0" />
|
||||
<!-- Native XML users input -->
|
||||
<filter
|
||||
inGroup="user-xml=>user"
|
||||
class="PKP\plugins\importexport\users\filter\UserXmlPKPUserFilter"
|
||||
isTemplate="0" />
|
||||
<!-- Native XML usergroup output -->
|
||||
<filter
|
||||
inGroup="usergroup=>user-xml"
|
||||
class="PKP\plugins\importexport\users\filter\UserGroupNativeXmlFilter"
|
||||
isTemplate="0" />
|
||||
<!-- Native XML usergroup input -->
|
||||
<filter
|
||||
inGroup="user-xml=>usergroup"
|
||||
class="PKP\plugins\importexport\users\filter\NativeXmlUserGroupFilter"
|
||||
isTemplate="0" />
|
||||
</filters>
|
||||
</filterConfig>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup plugins_importexport_users User import/export plugin
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file plugins/importexport/users/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup plugins_importexport_users
|
||||
*
|
||||
* @brief Wrapper for XML user import/export plugin.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \APP\plugins\importexport\users\UserImportExportPlugin();
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
* plugins/importexport/users/pkp-users.xsd
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* Schema describing native XML import/export elements specific to OMP
|
||||
-->
|
||||
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://pkp.sfu.ca" xmlns:pkp="http://pkp.sfu.ca" elementFormDefault="qualified">
|
||||
|
||||
<!--
|
||||
- Base the user import/export on the User database model.
|
||||
-->
|
||||
<include schemaLocation="../../../plugins/importexport/native/pkp-native.xsd" />
|
||||
|
||||
<!--
|
||||
- User-related Elements
|
||||
-->
|
||||
|
||||
<!-- A password complex type -->
|
||||
<complexType name="password">
|
||||
<sequence>
|
||||
<element name="value" type="string" minOccurs="1" maxOccurs="1" />
|
||||
</sequence>
|
||||
<attribute name="is_disabled" type="boolean" default="false" />
|
||||
<attribute name="must_change" type="boolean" default="false" />
|
||||
<attribute name="encryption" type="string" />
|
||||
</complexType>
|
||||
|
||||
<!-- Permit "users" as a root element -->
|
||||
<element name="users">
|
||||
<complexType>
|
||||
<sequence>
|
||||
<element name="user" type="pkp:user" minOccurs="1" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<!-- A user -->
|
||||
<complexType name="user">
|
||||
<complexContent>
|
||||
<extension base="pkp:identity">
|
||||
<sequence>
|
||||
<element name="username" type="string" minOccurs="1" maxOccurs="1" />
|
||||
<element name="gossip" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="signature" type="pkp:localizedNode" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="password" type="pkp:password" minOccurs="1" maxOccurs="1" />
|
||||
<element name="date_registered" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="date_last_login" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="date_last_email" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="date_validated" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="inline_help" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="auth_string" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="phone" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="mailing_address" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="billing_address" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="locales" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="disabled_reason" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="user_group_ref" type="string" maxOccurs="unbounded" />
|
||||
<element name="review_interests" type="string" minOccurs="0" maxOccurs="1" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
<!-- Permit "user" as a root element -->
|
||||
<element name="user" type="pkp:user" />
|
||||
|
||||
<!--
|
||||
- Composite / root elements
|
||||
-->
|
||||
<element name="PKPUsers">
|
||||
<complexType>
|
||||
<sequence>
|
||||
<element ref="pkp:user_groups" maxOccurs="1" />
|
||||
<element ref="pkp:users" maxOccurs="1" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
</element>
|
||||
</schema>
|
||||
Reference in New Issue
Block a user