From 757f58ffc78f14580f3f94fe04122d177c8d0c22 Mon Sep 17 00:00:00 2001
From: withanage
Date: Tue, 22 Oct 2024 09:16:01 +0200
Subject: [PATCH 01/26] customized page not found error
---
classes/core/Dispatcher.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/classes/core/Dispatcher.php b/classes/core/Dispatcher.php
index 5d03720f640..1e8d3455671 100644
--- a/classes/core/Dispatcher.php
+++ b/classes/core/Dispatcher.php
@@ -304,10 +304,10 @@ public function _cacheContent(string $contents): string
/**
* Handle a 404 error (page not found).
*/
- public static function handle404()
+ public static function handle404(string $message = "404 Not Found"): void
{
header('HTTP/1.0 404 Not Found');
- echo "404 Not Found
\n";
+ echo "" . htmlspecialchars($message) . "
\n";
exit;
}
}
From e62b1aad9452b63cb109ba97989ba9983f08cba1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?=
Date: Thu, 12 Sep 2024 11:31:44 +0200
Subject: [PATCH 02/26] pkp/pkp-lib#10392 Initial Masthead Styling
---
templates/frontend/pages/editorialHistory.tpl | 44 +++++++++----------
.../frontend/pages/editorialMasthead.tpl | 14 +++---
2 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/templates/frontend/pages/editorialHistory.tpl b/templates/frontend/pages/editorialHistory.tpl
index bf96d087ce4..0fc9ca8f8e8 100644
--- a/templates/frontend/pages/editorialHistory.tpl
+++ b/templates/frontend/pages/editorialHistory.tpl
@@ -18,32 +18,32 @@
{foreach from=$mastheadRoles item="mastheadRole"}
{if array_key_exists($mastheadRole->getId(), $mastheadUsers)}
{$mastheadRole->getLocalizedName()|escape}
-
+
{foreach from=$mastheadUsers[$mastheadRole->getId()] item="mastheadUser"}
-
-
- - {$mastheadUser['user']->getFullName()|escape}
+ {strip}
+
+ {foreach name="services" from=$mastheadUser['services'] item="service"}
+ {translate key="common.fromUntil" from=$service['dateStart'] until=$service['dateEnd']}
+ {if !$smarty.foreach.services.last}{translate key="common.commaListSeparator"}{/if}
+ {/foreach}
+
+ {$mastheadUser['user']->getFullName()|escape}
{if !empty($mastheadUser['user']->getLocalizedData('affiliation'))}
- - {$mastheadUser['user']->getLocalizedData('affiliation')|escape}
+ {$mastheadUser['user']->getLocalizedData('affiliation')|escape}
{/if}
- {if $mastheadUser['user']->getData('orcid')}
-
- {if $mastheadUser['user']->getData('orcidAccessToken')}
- {$orcidIcon}
- {/if}
-
- {$mastheadUser['user']->getData('orcid')|escape}
-
-
- {/if}
- -
- {foreach from=$mastheadUser['services'] item="service"}
-
- - {translate key="common.fromUntil" from=$service['dateStart'] until=$service['dateEnd']}
-
- {/foreach}
-
-
+ {/strip}
+ {if $mastheadUser['user']->getData('orcid')}
+
+ {if $mastheadUser['user']->getData('orcidAccessToken')}
+ {$orcidIcon}
+ {/if}
+
+ {$mastheadUser['user']->getData('orcid')|escape}
+
+
+ {/if}
+
{/foreach}
diff --git a/templates/frontend/pages/editorialMasthead.tpl b/templates/frontend/pages/editorialMasthead.tpl
index 3d6c3541c53..3c5659fd77b 100644
--- a/templates/frontend/pages/editorialMasthead.tpl
+++ b/templates/frontend/pages/editorialMasthead.tpl
@@ -17,16 +17,16 @@
{foreach from=$mastheadRoles item="mastheadRole"}
{if array_key_exists($mastheadRole->getId(), $mastheadUsers)}
{$mastheadRole->getLocalizedName()|escape}
-
+
{foreach from=$mastheadUsers[$mastheadRole->getId()] item="mastheadUser"}
-
-
- - {$mastheadUser['user']->getFullName()|escape}
+ {strip}
+ {$mastheadUser['dateStart']}
+ {$mastheadUser['user']->getFullName()|escape}
{if !empty($mastheadUser['user']->getLocalizedData('affiliation'))}
- - {$mastheadUser['user']->getLocalizedData('affiliation')|escape}
+ {$mastheadUser['user']->getLocalizedData('affiliation')|escape}
{/if}
- - {$mastheadUser['dateStart']}
-
+ {/strip}
{if $mastheadUser['user']->getData('orcid')}
{if $mastheadUser['user']->getData('orcidAccessToken')}
@@ -42,7 +42,7 @@
{/if}
{/foreach}
-
+
{capture assign=editorialHistoryUrl}{url page="about" op="editorialHistory" router=\PKP\core\PKPApplication::ROUTE_PAGE}{/capture}
{translate key="about.editorialMasthead.linkToEditorialHistory" url=$editorialHistoryUrl}
From fda710c02eb4f65acdd5a730fce4b36a81521814 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?=
Date: Mon, 21 Oct 2024 12:12:00 +0200
Subject: [PATCH 03/26] pkp/pkp-lib#10392 Compact orcid, ndash, same structure
applied to Peer Reviewers
---
locale/en/common.po | 2 +-
templates/frontend/pages/editorialHistory.tpl | 38 +++++++-------
.../frontend/pages/editorialMasthead.tpl | 52 +++++++++----------
3 files changed, 44 insertions(+), 48 deletions(-)
diff --git a/locale/en/common.po b/locale/en/common.po
index 80226c66569..ab4b5835857 100644
--- a/locale/en/common.po
+++ b/locale/en/common.po
@@ -2339,4 +2339,4 @@ msgid "common.sandbox"
msgstr "Application running in sandbox mode."
msgid "common.fromUntil"
-msgstr "{$from} - {$until}"
+msgstr "{$from} – {$until}"
diff --git a/templates/frontend/pages/editorialHistory.tpl b/templates/frontend/pages/editorialHistory.tpl
index 0fc9ca8f8e8..90d6cf18af9 100644
--- a/templates/frontend/pages/editorialHistory.tpl
+++ b/templates/frontend/pages/editorialHistory.tpl
@@ -22,28 +22,26 @@
{foreach from=$mastheadUsers[$mastheadRole->getId()] item="mastheadUser"}
-
{strip}
-
- {foreach name="services" from=$mastheadUser['services'] item="service"}
- {translate key="common.fromUntil" from=$service['dateStart'] until=$service['dateEnd']}
- {if !$smarty.foreach.services.last}{translate key="common.commaListSeparator"}{/if}
- {/foreach}
-
- {$mastheadUser['user']->getFullName()|escape}
- {if !empty($mastheadUser['user']->getLocalizedData('affiliation'))}
- {$mastheadUser['user']->getLocalizedData('affiliation')|escape}
+
+ {foreach name="services" from=$mastheadUser['services'] item="service"}
+ {translate key="common.fromUntil" from=$service['dateStart'] until=$service['dateEnd']}
+ {if !$smarty.foreach.services.last}{translate key="common.commaListSeparator"}{/if}
+ {/foreach}
+
+
+ {$mastheadUser['user']->getFullName()|escape}
+ {if $mastheadUser['user']->getData('orcid') && $mastheadUser['user']->getData('orcidAccessToken')}
+
+
+ {$orcidIcon}
+
+
{/if}
- {/strip}
- {if $mastheadUser['user']->getData('orcid')}
-
- {if $mastheadUser['user']->getData('orcidAccessToken')}
- {$orcidIcon}
- {/if}
-
- {$mastheadUser['user']->getData('orcid')|escape}
-
-
+
+ {if !empty($mastheadUser['user']->getLocalizedData('affiliation'))}
+ {$mastheadUser['user']->getLocalizedData('affiliation')|escape}
{/if}
-
+ {/strip}
{/foreach}
diff --git a/templates/frontend/pages/editorialMasthead.tpl b/templates/frontend/pages/editorialMasthead.tpl
index 3c5659fd77b..1d1d17fe8b7 100644
--- a/templates/frontend/pages/editorialMasthead.tpl
+++ b/templates/frontend/pages/editorialMasthead.tpl
@@ -21,22 +21,21 @@
{foreach from=$mastheadUsers[$mastheadRole->getId()] item="mastheadUser"}
-
{strip}
- {$mastheadUser['dateStart']}
- {$mastheadUser['user']->getFullName()|escape}
+ {translate key="common.fromUntil" from=$mastheadUser['dateStart'] until=""}
+
+ {$mastheadUser['user']->getFullName()|escape}
+ {if $mastheadUser['user']->getData('orcid') && $mastheadUser['user']->getData('orcidAccessToken')}
+
+
+ {$orcidIcon}
+
+
+ {/if}
+
{if !empty($mastheadUser['user']->getLocalizedData('affiliation'))}
{$mastheadUser['user']->getLocalizedData('affiliation')|escape}
{/if}
{/strip}
- {if $mastheadUser['user']->getData('orcid')}
-
- {if $mastheadUser['user']->getData('orcidAccessToken')}
- {$orcidIcon}
- {/if}
-
- {$mastheadUser['user']->getData('orcid')|escape}
-
-
- {/if}
{/foreach}
@@ -51,25 +50,24 @@
{if !empty($reviewers)}
{translate key="common.editorialMasthead.peerReviewers"}
{translate key="common.editorialMasthead.peerReviewers.description" year=$previousYear}
-
+
{foreach from=$reviewers item="reviewer"}
-
-
- - {$reviewer->getFullName()|escape}
- {if !empty($reviewer->getLocalizedData('affiliation'))}
- - {$reviewer->getLocalizedData('affiliation')|escape}
- {/if}
-
- {if $reviewer->getData('orcid')}
-
- {if $reviewer->getData('orcidAccessToken')}
- {$orcidIcon}
+ {strip}
+
+ {$reviewer->getFullName()|escape}
+ {if $reviewer->getData('orcid') && $reviewer->getData('orcidAccessToken')}
+
+
+ {$orcidIcon}
+
+
{/if}
-
- {$reviewer->getData('orcid')|escape}
-
- {/if}
+ {if !empty($reviewer->getLocalizedData('affiliation'))}
+ {$reviewer->getLocalizedData('affiliation')|escape}
+ {/if}
+ {/strip}
{/foreach}
From f28675c1152856bf8c289d5f98ae580bfc59829c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?=
Date: Tue, 22 Oct 2024 10:09:12 +0200
Subject: [PATCH 04/26] pkp/pkp-lib#10392 Added aria-label for orcid link
---
locale/en/common.po | 3 +++
templates/frontend/pages/editorialHistory.tpl | 2 +-
templates/frontend/pages/editorialMasthead.tpl | 4 ++--
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/locale/en/common.po b/locale/en/common.po
index ab4b5835857..e2f967f80eb 100644
--- a/locale/en/common.po
+++ b/locale/en/common.po
@@ -172,6 +172,9 @@ msgstr "Editorial History Page"
msgid "common.editorialHistory.page.description"
msgstr "This section lists past contributors."
+msgid "common.editorialHistory.page.orcidLink"
+msgstr "View {$name} ORCID profile"
+
msgid "common.name"
msgstr "Name"
diff --git a/templates/frontend/pages/editorialHistory.tpl b/templates/frontend/pages/editorialHistory.tpl
index 90d6cf18af9..694f441f190 100644
--- a/templates/frontend/pages/editorialHistory.tpl
+++ b/templates/frontend/pages/editorialHistory.tpl
@@ -32,7 +32,7 @@
{$mastheadUser['user']->getFullName()|escape}
{if $mastheadUser['user']->getData('orcid') && $mastheadUser['user']->getData('orcidAccessToken')}
-
+ getFullName()|escape}">
{$orcidIcon}
diff --git a/templates/frontend/pages/editorialMasthead.tpl b/templates/frontend/pages/editorialMasthead.tpl
index 1d1d17fe8b7..8226a5c51b5 100644
--- a/templates/frontend/pages/editorialMasthead.tpl
+++ b/templates/frontend/pages/editorialMasthead.tpl
@@ -26,7 +26,7 @@
{$mastheadUser['user']->getFullName()|escape}
{if $mastheadUser['user']->getData('orcid') && $mastheadUser['user']->getData('orcidAccessToken')}
-
+ getFullName()|escape}">
{$orcidIcon}
@@ -58,7 +58,7 @@
{$reviewer->getFullName()|escape}
{if $reviewer->getData('orcid') && $reviewer->getData('orcidAccessToken')}
-
+ getFullName()|escape}">
{$orcidIcon}
From 270bb11cc060202ef27a29094e59f2e08c5db8cc Mon Sep 17 00:00:00 2001
From: Nate Wright
Date: Tue, 22 Oct 2024 22:40:47 +0100
Subject: [PATCH 05/26] pkp/pkp-lib#10521 Add hooks to extend Publisher Library
categories (#10534)
---
classes/file/PKPLibraryFileManager.php | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/classes/file/PKPLibraryFileManager.php b/classes/file/PKPLibraryFileManager.php
index 877c945f982..78cede096bc 100644
--- a/classes/file/PKPLibraryFileManager.php
+++ b/classes/file/PKPLibraryFileManager.php
@@ -20,6 +20,7 @@
use PKP\context\LibraryFile;
use PKP\context\LibraryFileDAO;
use PKP\db\DAORegistry;
+use PKP\plugins\Hook;
class PKPLibraryFileManager extends PrivateFileManager
{
@@ -168,6 +169,7 @@ public function getFileSuffixFromType($type)
/**
* Get the type => suffix mapping array
*
+ * @hook PublisherLibrary::types::suffixes [[&$map]]
* @return array
*/
public function &getTypeSuffixMap()
@@ -178,6 +180,7 @@ public function &getTypeSuffixMap()
LibraryFile::LIBRARY_FILE_TYPE_REPORT => 'REP',
LibraryFile::LIBRARY_FILE_TYPE_OTHER => 'OTH'
];
+ Hook::call('PublisherLibrary::types::suffixes', [&$map]);
return $map;
}
@@ -199,6 +202,7 @@ public function getNameFromType($type)
/**
* Get the type => locale key mapping array
*
+ * @hook PublisherLibrary::types::titles [[&$map]]
* @return array
*/
public function &getTypeTitleKeyMap()
@@ -209,6 +213,7 @@ public function &getTypeTitleKeyMap()
LibraryFile::LIBRARY_FILE_TYPE_REPORT => 'settings.libraryFiles.category.reports',
LibraryFile::LIBRARY_FILE_TYPE_OTHER => 'settings.libraryFiles.category.other'
];
+ Hook::call('PublisherLibrary::types::titles', [&$map]);
return $map;
}
@@ -226,6 +231,7 @@ public function getTitleKeyFromType($type)
/**
* Get the type => name mapping array
*
+ * @hook PublisherLibrary::types::names [[&$typeNameMap]]
* @return array
*/
public function &getTypeNameMap()
@@ -236,6 +242,7 @@ public function &getTypeNameMap()
LibraryFile::LIBRARY_FILE_TYPE_REPORT => 'reports',
LibraryFile::LIBRARY_FILE_TYPE_OTHER => 'other',
];
+ Hook::call('PublisherLibrary::types::names', [&$typeNameMap]);
return $typeNameMap;
}
}
From e2c15b794aa9daad130630bff590f70ea6258434 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?=
Date: Wed, 23 Oct 2024 13:00:49 +0200
Subject: [PATCH 06/26] pkp/pkp-lib#7495 Expose componentForms from
dashboardStore
---
pages/dashboard/PKPDashboardHandlerNext.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pages/dashboard/PKPDashboardHandlerNext.php b/pages/dashboard/PKPDashboardHandlerNext.php
index 9d6b3552047..94d69703315 100644
--- a/pages/dashboard/PKPDashboardHandlerNext.php
+++ b/pages/dashboard/PKPDashboardHandlerNext.php
@@ -158,12 +158,14 @@ public function index($args, $request)
'dashboardPage' => $this->dashboardPage,
'countPerPage' => $this->perPage,
'filtersForm' => $filtersForm->getConfig(),
- 'contributorForm' => $contributorForm->getConfig(),
'views' => $this->getViews(),
'columns' => $this->getColumns(),
'publicationSettings' => [
'supportsCitations' => !!$context->getData('citations'),
'identifiersEnabled' => $identifiersEnabled,
+ ],
+ 'componentForms' => [
+ 'contributorForm' => $contributorForm->getConfig(),
]
]
]);
From 6882fa48c8bc68992843ab07d010bd6303f77d4d Mon Sep 17 00:00:00 2001
From: Nate Wright
Date: Thu, 24 Oct 2024 13:01:56 +0100
Subject: [PATCH 07/26] pkp/pkp-lib#10529 Remove workaround to FieldOptions
orderable bug (#10530)
---
.../forms/context/PKPAppearanceSetupForm.php | 23 ++++---------------
1 file changed, 4 insertions(+), 19 deletions(-)
diff --git a/classes/components/forms/context/PKPAppearanceSetupForm.php b/classes/components/forms/context/PKPAppearanceSetupForm.php
index 84c05c16c7f..684d037c1c2 100644
--- a/classes/components/forms/context/PKPAppearanceSetupForm.php
+++ b/classes/components/forms/context/PKPAppearanceSetupForm.php
@@ -43,33 +43,18 @@ public function __construct($action, $locales, $context, $baseUrl, $temporaryFil
$this->action = $action;
$this->locales = $locales;
$sidebarOptions = [];
- $enabledOptions = [];
- $disabledOptions = [];
$currentBlocks = (array) $context->getData('sidebar');
$plugins = PluginRegistry::loadCategory('blocks', true);
- foreach ($currentBlocks as $plugin) {
- if (isset($plugins[$plugin])) {
- $enabledOptions[] = [
- 'value' => $plugin,
- 'label' => htmlspecialchars($plugins[$plugin]->getDisplayName()),
- ];
- }
- }
-
foreach ($plugins as $pluginName => $plugin) {
- if (!in_array($pluginName, $currentBlocks)) {
- $disabledOptions[] = [
- 'value' => $pluginName,
- 'label' => htmlspecialchars($plugin->getDisplayName()),
- ];
- }
+ $sidebarOptions[] = [
+ 'value' => $pluginName,
+ 'label' => htmlspecialchars($plugin->getDisplayName()),
+ ];
}
- $sidebarOptions = array_merge($enabledOptions, $disabledOptions);
-
$this->addField(new FieldUploadImage('pageHeaderLogoImage', [
'label' => __('manager.setup.logo'),
'value' => $context->getData('pageHeaderLogoImage'),
From b4bb4998b136322019e59a2ccc5de439c774e7bc Mon Sep 17 00:00:00 2001
From: Nate Wright
Date: Fri, 18 Oct 2024 10:18:53 +0100
Subject: [PATCH 08/26] pkp/pkp-lib#10492 Add support for module script tags to
TemplateManager
---
classes/template/PKPTemplateManager.php | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/classes/template/PKPTemplateManager.php b/classes/template/PKPTemplateManager.php
index d458dfebc8a..a1161ab081e 100644
--- a/classes/template/PKPTemplateManager.php
+++ b/classes/template/PKPTemplateManager.php
@@ -578,6 +578,7 @@ public function addJavaScript(string $name, string $script, array $args = []): v
'priority' => self::STYLE_SEQUENCE_NORMAL,
'contexts' => ['frontend'],
'inline' => false,
+ 'type' => 'text/javascript',
],
$args
);
@@ -587,6 +588,7 @@ public function addJavaScript(string $name, string $script, array $args = []): v
$this->_javaScripts[$context][$args['priority']][$name] = [
'script' => $script,
'inline' => $args['inline'],
+ 'type' => $args['type'],
];
}
}
@@ -2196,12 +2198,12 @@ public function smartyLoadScript($params, $smarty)
foreach ($scripts as $priorityList) {
foreach ($priorityList as $name => $data) {
if ($data['inline']) {
- $output .= '';
+ $output .= '';
} else {
if ($appVersion && strpos($data['script'], '?') === false) {
$data['script'] .= '?v=' . $appVersion;
}
- $output .= '';
+ $output .= '';
}
}
}
From 7618dcafe8940ffc22fbacecdcbbc048fa18f82a Mon Sep 17 00:00:00 2001
From: Kaitlin Newson
Date: Fri, 11 Oct 2024 15:57:13 -0300
Subject: [PATCH 09/26] pkp/pkp-lib#10365 update onix filter for xml format
---
classes/xml/XMLParserDOMHandler.php | 14 ++--
classes/xml/XMLParserHandler.php | 2 +-
xml/onixFilter.xsl | 103 ++++++++++++++++------------
3 files changed, 67 insertions(+), 52 deletions(-)
diff --git a/classes/xml/XMLParserDOMHandler.php b/classes/xml/XMLParserDOMHandler.php
index b32b05d5759..e3580e34fdd 100644
--- a/classes/xml/XMLParserDOMHandler.php
+++ b/classes/xml/XMLParserDOMHandler.php
@@ -24,13 +24,13 @@
class XMLParserDOMHandler extends XMLParserHandler
{
- /** @var Root node */
+ /** @var ?XMLNode Root node */
public ?XMLNode $rootNode;
- /** @var The node currently being parsed */
+ /** @var ?XMLNode The node currently being parsed */
public ?XMLNode $currentNode = null;
- /** @var string reference to the current data */
+ /** @var ?string reference to the current data */
public ?string $currentData = null;
/** @var XMLNode[] */
@@ -46,7 +46,7 @@ public function __construct()
/**
* Callback function to act as the start element handler.
*/
- public function startElement(XMLParser|PKPXMLParser $parser, string $tag, array $attributes) : void
+ public function startElement(XMLParser|PKPXMLParser $parser, string $tag, array $attributes): void
{
$this->currentData = null;
$node = new XMLNode($tag);
@@ -65,7 +65,7 @@ public function startElement(XMLParser|PKPXMLParser $parser, string $tag, array
/**
* Callback function to act as the end element handler.
*/
- public function endElement(XMLParser|PKPXMLParser $parser, string $tag)
+ public function endElement(XMLParser|PKPXMLParser $parser, string $tag): void
{
$this->currentNode->setValue($this->currentData);
$this->currentNode = & $this->currentNode->getParent();
@@ -75,7 +75,7 @@ public function endElement(XMLParser|PKPXMLParser $parser, string $tag)
/**
* Callback function to act as the character data handler.
*/
- public function characterData(XMLParser|PKPXMLParser $parser, string $data)
+ public function characterData(XMLParser|PKPXMLParser $parser, string $data): void
{
$this->currentData .= $data;
}
@@ -83,7 +83,7 @@ public function characterData(XMLParser|PKPXMLParser $parser, string $data)
/**
* Returns a reference to the root node of the tree representing the document.
*/
- public function getResult() : mixed
+ public function getResult(): mixed
{
return $this->rootNode;
}
diff --git a/classes/xml/XMLParserHandler.php b/classes/xml/XMLParserHandler.php
index ddb5741bd5a..e63af2f4941 100644
--- a/classes/xml/XMLParserHandler.php
+++ b/classes/xml/XMLParserHandler.php
@@ -42,7 +42,7 @@ public function characterData(PKPXMLParser $parser, string $data)
* Returns a resulting data structure representing the parsed content.
* The format of this object is specific to the handler.
*/
- abstract public function getResult() : mixed;
+ abstract public function getResult(): mixed;
}
if (!PKP_STRICT_MODE) {
diff --git a/xml/onixFilter.xsl b/xml/onixFilter.xsl
index 3da7ef5a193..2ad5a3dd44e 100644
--- a/xml/onixFilter.xsl
+++ b/xml/onixFilter.xsl
@@ -3,59 +3,74 @@
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ()
+
+
+
+
+
+
+
+
+
+
-
-
-
- ()
-
-
-
-
-
-
-
From f27627882174fb1224d0a5e89fedd982ee32abf5 Mon Sep 17 00:00:00 2001
From: Kaitlin Newson
Date: Tue, 22 Oct 2024 13:42:32 -0300
Subject: [PATCH 10/26] fix library file form
---
controllers/grid/settings/library/form/NewLibraryFileForm.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/controllers/grid/settings/library/form/NewLibraryFileForm.php b/controllers/grid/settings/library/form/NewLibraryFileForm.php
index 51dd699e75e..9caee989540 100644
--- a/controllers/grid/settings/library/form/NewLibraryFileForm.php
+++ b/controllers/grid/settings/library/form/NewLibraryFileForm.php
@@ -43,10 +43,10 @@ public function __construct(int $contextId)
*
* @see Form::readInputData()
*/
- public function readInputData()
+ public function readInputData(): void
{
$this->readUserVars(['temporaryFileId']);
- return parent::readInputData();
+ parent::readInputData();
}
/**
From af501d2e3d0bcec2b0b57986349bc1280f21b6dc Mon Sep 17 00:00:00 2001
From: Taslan Graham
Date: Tue, 22 Oct 2024 13:43:53 -0500
Subject: [PATCH 11/26] pkp/pkp-lib#10537 Add available editorial decisions to
submission's stages data
---
classes/submission/maps/Schema.php | 84 +++++++++++++++++++++++++++---
schemas/submission.json | 15 ++++++
2 files changed, 92 insertions(+), 7 deletions(-)
diff --git a/classes/submission/maps/Schema.php b/classes/submission/maps/Schema.php
index 0924f1915f1..54f78ccecab 100644
--- a/classes/submission/maps/Schema.php
+++ b/classes/submission/maps/Schema.php
@@ -20,9 +20,9 @@
use Illuminate\Support\Enumerable;
use Illuminate\Support\LazyCollection;
use PKP\db\DAORegistry;
+use PKP\decision\DecisionType;
use PKP\plugins\Hook;
use PKP\plugins\PluginRegistry;
-use PKP\query\Query;
use PKP\security\Role;
use PKP\services\PKPSchemaService;
use PKP\stageAssignment\StageAssignment;
@@ -31,6 +31,7 @@
use PKP\submission\reviewRound\ReviewRound;
use PKP\submission\reviewRound\ReviewRoundDAO;
use PKP\submissionFile\SubmissionFile;
+use PKP\user\User;
use PKP\userGroup\UserGroup;
use PKP\workflow\WorkflowStageDAO;
@@ -527,7 +528,7 @@ public function getPropertyStages(Submission $submission): array
$currentUserAssignedRoles = [];
$stageAssignmentsOverview = [];
if ($currentUser) {
- // FIXME - $stageAssignments are just temporarly added until https://github.com/pkp/pkp-lib/issues/10480 is ready
+ // FIXME - $stageAssignments are just temporarily added until https://github.com/pkp/pkp-lib/issues/10480 is ready
$currentRoles = array_map(
function (Role $role) {
return $role->getId();
@@ -556,10 +557,10 @@ function (Role $role) {
foreach ($stageAssignments as $stageAssignment) {
$userGroup = Repo::userGroup()->get($stageAssignment->userGroupId);
$stageAssignmentsOverview[] = [
- "roleId" => $userGroup->getRoleId(),
- "recommendOnly" => $stageAssignment->recommendOnly,
- "canChangeMetadata" => $stageAssignment->canChangeMetadata,
- "userId" => $stageAssignment->userId
+ 'roleId' => $userGroup->getRoleId(),
+ 'recommendOnly' => $stageAssignment->recommendOnly,
+ 'canChangeMetadata' => $stageAssignment->canChangeMetadata,
+ 'userId' => $stageAssignment->userId
];
}
}
@@ -568,7 +569,7 @@ function (Role $role) {
$stage['stageAssignments'] = $stageAssignmentsOverview;
if(!$stage['currentUserAssignedRoles']) {
if(in_array(Role::ROLE_ID_MANAGER, $currentRoles)) {
- $stage['currentUserAssignedRoles'][] = Role::ROLE_ID_MANAGER;
+ $stage['currentUserAssignedRoles'][] = Role::ROLE_ID_MANAGER;
}
}
// Stage-specific statuses
@@ -649,6 +650,10 @@ function (Role $role) {
break;
}
+
+ $availableEditorialDecisions = $this->getAvailableEditorialDecisions($stageId, $submission);
+ $stage['availableEditorialDecisions'] = array_map(fn (DecisionType $decisionType) => ['id' => $decisionType->getDecision(), 'label' => $decisionType->getLabel()], $availableEditorialDecisions);
+
$stages[] = $stage;
}
@@ -722,4 +727,69 @@ protected function appSpecificProps(): array
{
return [];
}
+
+ /**
+ * Implement by a child class to get available editorial decisions data for a stage of a submission.
+ */
+ protected function getAvailableEditorialDecisions(int $stageId, Submission $submission): array
+ {
+ return [];
+ }
+
+ /**
+ * Check if a user can make Decisions or Recommendations on a submission's stage
+ */
+ protected function checkDecisionPermissions(int $stageId, Submission $submission, User $user, int $contextId): array
+ {
+ /** @var StageAssignment[] $editorsStageAssignments*/
+ $editorsStageAssignments = StageAssignment::withSubmissionIds([$submission->getId()])
+ ->withStageIds([$stageId])
+ ->withRoleIds([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR])
+ ->withUserId($user->getId())
+ ->get();
+
+ $makeRecommendation = $makeDecision = false;
+ // if the user is assigned several times in an editorial role, check his/her assignments permissions i.e.
+ // if the user is assigned with both possibilities: to only recommend as well as make decision
+ foreach ($editorsStageAssignments as $editorsStageAssignment) {
+ if (!$editorsStageAssignment->recommendOnly) {
+ $makeDecision = true;
+ } else {
+ $makeRecommendation = true;
+ }
+ }
+
+ // If user is not assigned to the submission,
+ // see if the user is manager, and
+ // if the group is recommendOnly
+ if (!$makeRecommendation && !$makeDecision) {
+ $userGroups = Repo::userGroup()->userUserGroups($user->getId(), $contextId);
+ foreach ($userGroups as $userGroup) {
+ if (in_array($userGroup->getRoleId(), [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN])) {
+ if (!$userGroup->getRecommendOnly()) {
+ $makeDecision = true;
+ } else {
+ $makeRecommendation = true;
+ }
+ }
+ }
+ }
+
+ // if the user can make recommendations, check whether there are any decisions that can be made given
+ // the stage that we are operating into.
+ $isOnlyRecommending = $makeRecommendation && !$makeDecision;
+
+ if ($isOnlyRecommending) {
+ if (!empty(Repo::decision()->getDecisionTypesMadeByRecommendingUsers($stageId))) {
+ // If there are any, then the user can be considered a decision user.
+ $makeDecision = true;
+ }
+ }
+
+ return [
+ 'canMakeDecision' => $makeDecision,
+ 'canMakeRecommendation' => $makeRecommendation,
+ 'isOnlyRecommending' => $isOnlyRecommending
+ ];
+ }
}
diff --git a/schemas/submission.json b/schemas/submission.json
index 9eb11dca2ac..0dfac389b9c 100644
--- a/schemas/submission.json
+++ b/schemas/submission.json
@@ -265,6 +265,21 @@
"type": "boolean"
}
}
+ },
+ "availableEditorialDecisions": {
+ "description": "The editorial decisions that are available for this stage.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "label": {
+ "type": "string"
+ }
+ }
+ }
}
}
}
From 29e73e7facbc9e1effeec8fc622fe34992c60e3d Mon Sep 17 00:00:00 2001
From: Erik Hanson
Date: Wed, 23 Oct 2024 14:24:11 -0700
Subject: [PATCH 12/26] pkp/pkp-lib#10547 Thank reviewer functionality produces
a fatal error
---
controllers/grid/users/reviewer/form/ThankReviewerForm.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/controllers/grid/users/reviewer/form/ThankReviewerForm.php b/controllers/grid/users/reviewer/form/ThankReviewerForm.php
index fd23eab0b20..ee937275080 100644
--- a/controllers/grid/users/reviewer/form/ThankReviewerForm.php
+++ b/controllers/grid/users/reviewer/form/ThankReviewerForm.php
@@ -125,7 +125,7 @@ public function execute(...$functionArgs)
Hook::call('ThankReviewerForm::thankReviewer', [$submission, $reviewAssignment, $mailable]);
- (new SendReviewToOrcid($submission, $context, $reviewAssignment))->execute();
+ (new SendReviewToOrcid($reviewAssignment->getId()))->execute();
if (!$this->getData('skipEmail')) {
$mailable->setData(Locale::getLocale());
From d5589c704e2a1ef25fdf92c28390bd164be9c899 Mon Sep 17 00:00:00 2001
From: Dimitris Efstathiou
Date: Thu, 24 Oct 2024 11:23:49 +0300
Subject: [PATCH 13/26] pkp/pkp-lib#10550 Remove "removeUserRoles" from the
invitation process
---
.../UserRoleAssignmentInvite.php | 4 +-
.../UserRoleAssignmentReceiveController.php | 9 ----
.../UserRoleAssignmentInvitePayload.php | 19 --------
.../UserRoleAssignmentInviteResource.php | 5 +-
.../rules/NoUserGroupChangesRule.php | 9 +---
.../rules/RemoveUserGroupRule.php | 48 -------------------
.../UserRoleAssignmentInvitationNotify.php | 18 -------
locale/en/emails.po | 9 ----
locale/en/invitation.po | 3 --
9 files changed, 5 insertions(+), 119 deletions(-)
delete mode 100644 classes/invitation/invitations/userRoleAssignment/rules/RemoveUserGroupRule.php
diff --git a/classes/invitation/invitations/userRoleAssignment/UserRoleAssignmentInvite.php b/classes/invitation/invitations/userRoleAssignment/UserRoleAssignmentInvite.php
index eb79e1b62d0..e3dafeb0e5d 100644
--- a/classes/invitation/invitations/userRoleAssignment/UserRoleAssignmentInvite.php
+++ b/classes/invitation/invitations/userRoleAssignment/UserRoleAssignmentInvite.php
@@ -45,7 +45,6 @@ class UserRoleAssignmentInvite extends Invitation implements IApiHandleable
protected array $notAccessibleAfterInvite = [
'userGroupsToAdd',
- 'userGroupsToRemove',
];
protected array $notAccessibleBeforeInvite = [
@@ -164,8 +163,7 @@ public function getValidationRules(ValidationContext $validationContext = Valida
$validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE
) {
$invitationValidationRules[Invitation::VALIDATION_RULE_GENERIC][] = new NoUserGroupChangesRule(
- $this->getPayload()->userGroupsToAdd,
- $this->getPayload()->userGroupsToRemove
+ $this->getPayload()->userGroupsToAdd
);
$invitationValidationRules[Invitation::VALIDATION_RULE_GENERIC][] = new UserMustExistRule($this->getUserId());
$invitationValidationRules[Invitation::VALIDATION_RULE_GENERIC][] = new EmailMustNotExistRule($this->getEmail());
diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php b/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php
index dfaf39094ef..d27d82e7afa 100644
--- a/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php
+++ b/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php
@@ -110,15 +110,6 @@ public function finalize(Request $illuminateRequest): JsonResponse
}
}
- foreach ($this->invitation->getPayload()->userGroupsToRemove as $userUserGroup) {
- $userGroupHelper = UserGroupHelper::fromArray($userUserGroup);
- Repo::userGroup()->endAssignments(
- $this->invitation->getContextId(),
- $user->getId(),
- $userGroupHelper->userGroupId
- );
- }
-
foreach ($this->invitation->getPayload()->userGroupsToAdd as $userUserGroup) {
$userGroupHelper = UserGroupHelper::fromArray($userUserGroup);
diff --git a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
index c4dc6cebcdd..ef886437c58 100644
--- a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
+++ b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
@@ -21,7 +21,6 @@
use PKP\invitation\invitations\userRoleAssignment\rules\AllowedKeysRule;
use PKP\invitation\invitations\userRoleAssignment\rules\NotNullIfPresent;
use PKP\invitation\invitations\userRoleAssignment\rules\ProhibitedIncludingNull;
-use PKP\invitation\invitations\userRoleAssignment\rules\RemoveUserGroupRule;
use PKP\invitation\invitations\userRoleAssignment\rules\UserGroupExistsRule;
use PKP\invitation\invitations\userRoleAssignment\rules\UsernameExistsRule;
use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite;
@@ -39,7 +38,6 @@ public function __construct(
public ?string $emailSubject = null,
public ?string $emailBody = null,
public ?array $userGroupsToAdd = null,
- public ?array $userGroupsToRemove = null,
public ?bool $passwordHashed = null,
public ?string $sendEmailAddress = null,
)
@@ -146,23 +144,6 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
],
'userGroupsToAdd.*.masthead' => 'required|bool',
'userGroupsToAdd.*.dateStart' => 'required|date|after_or_equal:today',
- 'userGroupsToRemove' => [
- 'sometimes',
- 'bail',
- new ProhibitedIncludingNull(is_null($invitation->getUserId())),
- Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE, ValidationContext::VALIDATION_CONTEXT_FINALIZE]), ['nullable']),
- ],
- 'userGroupsToRemove.*' => [
- 'array',
- new AllowedKeysRule(['userGroupId']),
- ],
- 'userGroupsToRemove.*.userGroupId' => [
- 'distinct',
- 'required',
- 'integer',
- new UserGroupExistsRule(),
- new RemoveUserGroupRule($invitation),
- ],
'userOrcid' => [
Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE, ValidationContext::VALIDATION_CONTEXT_FINALIZE]), ['nullable']),
'orcid'
diff --git a/classes/invitation/invitations/userRoleAssignment/resources/UserRoleAssignmentInviteResource.php b/classes/invitation/invitations/userRoleAssignment/resources/UserRoleAssignmentInviteResource.php
index a6eb4f6a073..6d94e27fc8f 100644
--- a/classes/invitation/invitations/userRoleAssignment/resources/UserRoleAssignmentInviteResource.php
+++ b/classes/invitation/invitations/userRoleAssignment/resources/UserRoleAssignmentInviteResource.php
@@ -53,7 +53,6 @@ public function toArray(Request $request)
'emailSubject' => $this->getPayload()->emailSubject,
'emailBody' => $this->getPayload()->emailBody,
'userGroupsToAdd' => $this->transformUserGroups($this->getPayload()->userGroupsToAdd),
- 'userGroupsToRemove' => $this->transformUserGroups($this->getPayload()->userGroupsToRemove),
'username' => $this->getPayload()->username,
'sendEmailAddress' => $this->getPayload()->sendEmailAddress,
'existingUser' => $this->transformUser($this->getExistingUser()),
@@ -62,7 +61,7 @@ public function toArray(Request $request)
}
/**
- * Transform the userGroupsToAdd or userGroupsToRemove to include related UserGroup data.
+ * Transform the userGroupsToAdd to include related UserGroup data.
*
* @param array|null $userGroups
* @return array
@@ -83,7 +82,7 @@ protected function transformUserGroups(?array $userGroups)
}
/**
- * Transform the userGroupsToAdd or userGroupsToRemove to include related UserGroup data.
+ * Transform the userGroupsToAdd to include related UserGroup data.
*
* @param array|null $userGroups
* @return array
diff --git a/classes/invitation/invitations/userRoleAssignment/rules/NoUserGroupChangesRule.php b/classes/invitation/invitations/userRoleAssignment/rules/NoUserGroupChangesRule.php
index e3208e983ff..fda1120f75b 100644
--- a/classes/invitation/invitations/userRoleAssignment/rules/NoUserGroupChangesRule.php
+++ b/classes/invitation/invitations/userRoleAssignment/rules/NoUserGroupChangesRule.php
@@ -19,21 +19,16 @@
class NoUserGroupChangesRule implements Rule
{
protected ?array $userGroupsToAdd;
- protected ?array $userGroupsToRemove;
protected string $validationContext;
- public function __construct(?array $userGroupsToAdd, ?array $userGroupsToRemove)
+ public function __construct(?array $userGroupsToAdd)
{
$this->userGroupsToAdd = $userGroupsToAdd;
- $this->userGroupsToRemove = $userGroupsToRemove;
}
public function passes($attribute, $value)
{
- return !(
- empty($this->userGroupsToAdd) &&
- empty($this->userGroupsToRemove)
- );
+ return !empty($this->userGroupsToAdd);
}
public function message()
diff --git a/classes/invitation/invitations/userRoleAssignment/rules/RemoveUserGroupRule.php b/classes/invitation/invitations/userRoleAssignment/rules/RemoveUserGroupRule.php
deleted file mode 100644
index a5e34704ca0..00000000000
--- a/classes/invitation/invitations/userRoleAssignment/rules/RemoveUserGroupRule.php
+++ /dev/null
@@ -1,48 +0,0 @@
-invitation = $invitation;
- }
-
- public function passes($attribute, $value)
- {
- // At this point, we know the user group exists; check if the user has it assigned
- if ($user = $this->invitation->getExistingUser()) {
- $userUserGroups = UserUserGroup::withUserId($user->getId())
- ->withUserGroupId($value) // The $value is the userGroupId
- ->get();
-
- return !$userUserGroups->isEmpty(); // Fail if the user doesn't have the group assigned
- }
-
- return false; // Fail if the user doesn't exist or isn't assigned the group
- }
-
- public function message()
- {
- return __('invitation.userRoleAssignment.validation.error.removeUserRoles.userGroupNotAssignedToUser');
- }
-}
\ No newline at end of file
diff --git a/classes/mail/mailables/UserRoleAssignmentInvitationNotify.php b/classes/mail/mailables/UserRoleAssignmentInvitationNotify.php
index bf45a7c6bb6..d11ee00fd8d 100644
--- a/classes/mail/mailables/UserRoleAssignmentInvitationNotify.php
+++ b/classes/mail/mailables/UserRoleAssignmentInvitationNotify.php
@@ -55,7 +55,6 @@ class UserRoleAssignmentInvitationNotify extends Mailable
protected static string $inviterName = 'inviterName';
protected static string $inviterRole = 'inviterRole';
protected static string $rolesAdded = 'rolesAdded';
- protected static string $rolesRemoved = 'rolesRemoved';
protected static string $existingRoles = 'existingRoles';
protected static string $acceptUrl = 'acceptUrl';
protected static string $declineUrl = 'declineUrl';
@@ -80,7 +79,6 @@ public static function getDataDescriptions(): array
$variables[static::$inviterName] = __('emailTemplate.variable.invitation.inviterName');
$variables[static::$inviterRole] = __('emailTemplate.variable.invitation.inviterRole');
$variables[static::$rolesAdded] = __('emailTemplate.variable.invitation.rolesAdded');
- $variables[static::$rolesRemoved] = __('emailTemplate.variable.invitation.rolesRemoved');
$variables[static::$existingRoles] = __('emailTemplate.variable.invitation.existingRoles');
$variables[static::$acceptUrl] = __('emailTemplate.variable.invitation.acceptUrl');
$variables[static::$declineUrl] = __('emailTemplate.variable.invitation.declineUrl');
@@ -183,24 +181,9 @@ public function setData(?string $locale = null): void
$existingUserGroupsTitle = __('emails.userRoleAssignmentInvitationNotify.alreadyAssignedRoles');
- $userGroupsRemovedTitle = __('emails.userRoleAssignmentInvitationNotify.removedRoles');
$existingUserGroups = '';
- $userGroupsRemoved = '';
if (isset($user)) {
- // Roles Removed
- foreach ($this->invitation->getPayload()->userGroupsToRemove as $userUserGroup) {
- $userGroupHelper = UserGroupHelper::fromArray($userUserGroup);
-
- $userGroup = Repo::userGroup()->get($userGroupHelper->userGroupId);
- $userUserGroups = UserUserGroup::withUserId($user->getId())
- ->withUserGroupId($userGroup->getId())
- ->withActive()
- ->get();
-
- $userGroupsRemoved = $this->getAllUserUserGroupSection($userUserGroups->toArray(), $userGroup, $context, $locale, $userGroupsRemovedTitle);
- }
-
// Existing Roles
$userGroups = Repo::userGroup()->getCollector()
->filterByContextIds([$this->invitation->getContextId()])
@@ -231,7 +214,6 @@ public function setData(?string $locale = null): void
static::$acceptUrl => $this->invitation->getActionURL(InvitationAction::ACCEPT),
static::$declineUrl => $this->invitation->getActionURL(InvitationAction::DECLINE),
static::$rolesAdded => $userGroupsAdded,
- static::$rolesRemoved => $userGroupsRemoved,
static::$existingRoles => $existingUserGroups,
static::EMAIL_TEMPLATE_STYLE_PROPERTY => $emailTemplateStyle,
]
diff --git a/locale/en/emails.po b/locale/en/emails.po
index e780ab5cbf0..69bfa81bae2 100644
--- a/locale/en/emails.po
+++ b/locale/en/emails.po
@@ -575,7 +575,6 @@ msgstr ""
" At {$contextName}, we value your privacy. As such, we have taken steps to ensure that we are fully GDPR compliant. These steps include you being accountable to enter your own data and choosing who can see what information. or additional information on how we handled your data, please refer to our Privacy Policy.
"
" {$existingRoles}
"
" {$rolesAdded}
"
-" {$rolesRemoved}
"
" On accepting the invite, you will be redirected to {$contextName}
"
" Feel free to contact me with any questions about the process.
"
" Accept Invitation
"
@@ -621,10 +620,6 @@ msgstr "Newly assigned roles
"
msgid "emails.userRoleAssignmentInvitationNotify.alreadyAssignedRoles"
msgstr "Already assigned roles
"
-#, fuzzy
-msgid "emails.userRoleAssignmentInvitationNotify.removedRoles"
-msgstr "Removed roles
"
-
#, fuzzy
msgid "emailTemplate.variable.invitation.recipientName"
msgstr "This is the name of the invitation recipient"
@@ -641,10 +636,6 @@ msgstr "This is the role of the sender of the invitation"
msgid "emailTemplate.variable.invitation.rolesAdded"
msgstr "This section describes the roles that will be added to the user upon the invitation acceptance"
-#, fuzzy
-msgid "emailTemplate.variable.invitation.rolesRemoved"
-msgstr "This section describes the roles that will be removed from the user upon the invitation acceptance"
-
#, fuzzy
msgid "emailTemplate.variable.invitation.existingRoles"
msgstr "This section describes the roles that the user already has."
diff --git a/locale/en/invitation.po b/locale/en/invitation.po
index 853e431cbf4..b65f09f074f 100644
--- a/locale/en/invitation.po
+++ b/locale/en/invitation.po
@@ -25,9 +25,6 @@ msgstr "At least one user group to remove must be defined"
msgid "invitation.userRoleAssignment.validation.error.removeUserRoles.cantRemoveFromNonExistingUser"
msgstr "Remove user roles can't be defined for not existing users."
-msgid "invitation.userRoleAssignment.validation.error.removeUserRoles.userGroupNotAssignedToUser"
-msgstr "The user group is not assigned to the invited user"
-
msgid "invitation.userRoleAssignment.validation.error.noUserGroupChanges"
msgstr "The invitation can not be dispatched because you have not defined any user group changes"
From 25299eb73d2feab7181e51644d4723bd9dac585d Mon Sep 17 00:00:00 2001
From: Dimitris Efstathiou
Date: Thu, 24 Oct 2024 11:26:06 +0300
Subject: [PATCH 14/26] pkp/pkp-lib#10550 Apply password validation rules
---
.../payload/UserRoleAssignmentInvitePayload.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
index ef886437c58..e4b1b0b732b 100644
--- a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
+++ b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
@@ -14,6 +14,7 @@
namespace PKP\invitation\invitations\userRoleAssignment\payload;
+use DAORegistry;
use Illuminate\Validation\Rule;
use PKP\invitation\core\enums\ValidationContext;
use PKP\invitation\core\InvitePayload;
@@ -52,6 +53,9 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
$context = $invitation->getContext();
$allowedLocales = $context->getSupportedFormLocales();
+ $siteDao = DAORegistry::getDAO('SiteDAO');
+ $site = $siteDao->getSite();
+
$validationRules = [
'givenName' => [
'bail',
@@ -124,6 +128,7 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
new NotNullIfPresent(),
'required_with:username',
'max:255',
+ 'min:' . $site->getMinPasswordLength(),
],
'userGroupsToAdd' => [
Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_INVITE),
From c12ca0fe3b4f72d54d0c663e66d85b254426fd06 Mon Sep 17 00:00:00 2001
From: Dimitris Efstathiou
Date: Thu, 24 Oct 2024 12:30:40 +0300
Subject: [PATCH 15/26] pkp/pkp-lib#10550 Adjust validation rules for
givenName, LastName, Affiliation, Country
---
.../UserRoleAssignmentInvitePayload.php | 18 +++++---
.../rules/PrimaryLocaleRequired.php | 44 +++++++++++++++++++
locale/en/invitation.po | 5 ++-
3 files changed, 59 insertions(+), 8 deletions(-)
create mode 100644 classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php
diff --git a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
index e4b1b0b732b..7e8d574c134 100644
--- a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
+++ b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
@@ -21,6 +21,7 @@
use PKP\invitation\invitations\userRoleAssignment\rules\AddUserGroupRule;
use PKP\invitation\invitations\userRoleAssignment\rules\AllowedKeysRule;
use PKP\invitation\invitations\userRoleAssignment\rules\NotNullIfPresent;
+use PKP\invitation\invitations\userRoleAssignment\rules\PrimaryLocaleRequired;
use PKP\invitation\invitations\userRoleAssignment\rules\ProhibitedIncludingNull;
use PKP\invitation\invitations\userRoleAssignment\rules\UserGroupExistsRule;
use PKP\invitation\invitations\userRoleAssignment\rules\UsernameExistsRule;
@@ -44,14 +45,13 @@ public function __construct(
)
{
parent::__construct(get_object_vars($this));
-
-
}
public function getValidationRules(UserRoleAssignmentInvite $invitation, ValidationContext $validationContext = ValidationContext::VALIDATION_CONTEXT_DEFAULT): array
{
$context = $invitation->getContext();
$allowedLocales = $context->getSupportedFormLocales();
+ $primaryLocale = $context->getPrimaryLocale();
$siteDao = DAORegistry::getDAO('SiteDAO');
$site = $siteDao->getSite();
@@ -65,9 +65,11 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
'sometimes',
'array',
- new AllowedKeysRule($allowedLocales), // Apply the custom rule
+ new AllowedKeysRule($allowedLocales),
+ new PrimaryLocaleRequired($primaryLocale),
],
'givenName.*' => [
+ 'nullable', // Make optional for other locales
'string',
'max:255',
],
@@ -75,13 +77,13 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
'bail',
Rule::excludeIf(!is_null($invitation->getUserId()) && $validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
new ProhibitedIncludingNull(!is_null($invitation->getUserId())),
- Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE]), ['nullable']),
- Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
+ Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE, ValidationContext::VALIDATION_CONTEXT_FINALIZE]), ['nullable']),
'sometimes',
'array',
- new AllowedKeysRule($allowedLocales), // Apply the custom rule
+ new AllowedKeysRule($allowedLocales),
],
'familyName.*' => [
+ 'nullable', // Make optional for all locales
'string',
'max:255',
],
@@ -93,9 +95,11 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
'sometimes',
'array',
- new AllowedKeysRule($allowedLocales), // Apply the custom rule
+ new AllowedKeysRule($allowedLocales),
+ new PrimaryLocaleRequired($primaryLocale),
],
'affiliation.*' => [
+ 'nullable', // Make optional for other locales
'string',
'max:255',
],
diff --git a/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php b/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php
new file mode 100644
index 00000000000..547a10c66c6
--- /dev/null
+++ b/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php
@@ -0,0 +1,44 @@
+primaryLocale = $primaryLocale;
+ }
+
+ public function passes($attribute, $value)
+ {
+ $providedLocales = array_filter($value);
+ if (!empty($providedLocales) && !array_key_exists($this->primaryLocale, $providedLocales)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function message()
+ {
+ return __('invitation.userRoleAssignment.validation.error.multilingual.primaryLocaleRequired', [
+ 'primaryLocale' => $this->primaryLocale,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/locale/en/invitation.po b/locale/en/invitation.po
index b65f09f074f..402116a7861 100644
--- a/locale/en/invitation.po
+++ b/locale/en/invitation.po
@@ -98,4 +98,7 @@ msgid "invitation.userRoleAssignment.userGroup.startDate.mustBeAfterToday"
msgstr "This attribute must have a value equal or after today"
msgid "invitation.validation.error.propertyProhibited"
-msgstr "The :attribute field is prohibited"
\ No newline at end of file
+msgstr "The :attribute field is prohibited"
+
+msgid "invitation.userRoleAssignment.validation.error.multilingual.primaryLocaleRequired"
+msgstr "A value for locale '{$primaryLocale}' is required"
\ No newline at end of file
From 012f6404ca5b360d8823a59c8135c5dbffe0e94e Mon Sep 17 00:00:00 2001
From: Dimitris Efstathiou
Date: Tue, 29 Oct 2024 13:38:02 +0200
Subject: [PATCH 16/26] pkp/pkp-lib#10550 Remove startDate validation - Field
validation rules fixes
---
.../handlers/api/UserRoleAssignmentReceiveController.php | 9 ++++++++-
.../payload/UserRoleAssignmentInvitePayload.php | 3 ++-
.../userRoleAssignment/rules/PrimaryLocaleRequired.php | 6 ++++--
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php b/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php
index d27d82e7afa..fc8506357bb 100644
--- a/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php
+++ b/classes/invitation/invitations/userRoleAssignment/handlers/api/UserRoleAssignmentReceiveController.php
@@ -15,6 +15,7 @@
namespace PKP\invitation\invitations\userRoleAssignment\handlers\api;
use APP\facades\Repo;
+use Carbon\Carbon;
use Core;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -113,10 +114,16 @@ public function finalize(Request $illuminateRequest): JsonResponse
foreach ($this->invitation->getPayload()->userGroupsToAdd as $userUserGroup) {
$userGroupHelper = UserGroupHelper::fromArray($userUserGroup);
+ $dateStart = Carbon::parse($userGroupHelper->dateStart)->startOfDay();
+ $today = Carbon::today();
+
+ // Use today's date if dateStart is in the past, otherwise keep dateStart
+ $effectiveDateStart = $dateStart->lessThan($today) ? $today->toDateString() : $dateStart->toDateString();
+
Repo::userGroup()->assignUserToGroup(
$user->getId(),
$userGroupHelper->userGroupId,
- $userGroupHelper->dateStart,
+ $effectiveDateStart,
$userGroupHelper->dateEnd,
isset($userGroupHelper->masthead) && $userGroupHelper->masthead
? UserUserGroupMastheadStatus::STATUS_ON
diff --git a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
index 7e8d574c134..9050d1824ca 100644
--- a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
+++ b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
@@ -109,6 +109,8 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
new ProhibitedIncludingNull(!is_null($invitation->getUserId())),
Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE]), ['nullable']),
Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
+ 'sometimes', // Applies the rule only if userCountry exists in the request
+ Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_REFINE),
'string',
'max:255',
],
@@ -152,7 +154,6 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
new AddUserGroupRule($invitation),
],
'userGroupsToAdd.*.masthead' => 'required|bool',
- 'userGroupsToAdd.*.dateStart' => 'required|date|after_or_equal:today',
'userOrcid' => [
Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE, ValidationContext::VALIDATION_CONTEXT_FINALIZE]), ['nullable']),
'orcid'
diff --git a/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php b/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php
index 547a10c66c6..20a87f95af2 100644
--- a/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php
+++ b/classes/invitation/invitations/userRoleAssignment/rules/PrimaryLocaleRequired.php
@@ -27,8 +27,10 @@ public function __construct($primaryLocale)
public function passes($attribute, $value)
{
- $providedLocales = array_filter($value);
- if (!empty($providedLocales) && !array_key_exists($this->primaryLocale, $providedLocales)) {
+ $providedLocales = array_keys($value);
+ if (!empty($providedLocales) &&
+ array_key_exists($this->primaryLocale, $value) &&
+ empty($value[$this->primaryLocale])) {
return false;
}
From f0338f1bd1c53fd846bff47a1a0c20213402c393 Mon Sep 17 00:00:00 2001
From: Dimitris Efstathiou
Date: Tue, 29 Oct 2024 18:03:30 +0200
Subject: [PATCH 17/26] pkp/pkp-lib#10550 Validation Rules fixxes
---
api/v1/invitations/InvitationController.php | 8 ++++++++
.../payload/UserRoleAssignmentInvitePayload.php | 12 +++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/api/v1/invitations/InvitationController.php b/api/v1/invitations/InvitationController.php
index 5176e332c14..0d1ea50d1db 100644
--- a/api/v1/invitations/InvitationController.php
+++ b/api/v1/invitations/InvitationController.php
@@ -221,6 +221,14 @@ public function authorize(PKPRequest $request, array &$args, array $roleAssignme
throw new Exception('This invitation does not support API handling');
}
+ if (in_array($actionName, $this->requiresOnlyId) && $this->invitation->getStatus() != InvitationStatus::INITIALIZED) {
+ throw new Exception('This action is not allowed');
+ }
+
+ if (in_array($actionName, $this->requiresIdAndKey) && $this->invitation->getStatus() != InvitationStatus::PENDING) {
+ throw new Exception('This action is not allowed');
+ }
+
$this->createInvitationHandler = $invitation->getCreateInvitationController($this->invitation);
$this->receiveInvitationHandler = $invitation->getReceiveInvitationController($this->invitation);
diff --git a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
index 9050d1824ca..38b685ad79c 100644
--- a/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
+++ b/classes/invitation/invitations/userRoleAssignment/payload/UserRoleAssignmentInvitePayload.php
@@ -66,13 +66,17 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
'sometimes',
'array',
new AllowedKeysRule($allowedLocales),
- new PrimaryLocaleRequired($primaryLocale),
],
'givenName.*' => [
'nullable', // Make optional for other locales
'string',
'max:255',
],
+ "givenName.{$primaryLocale}" => [
+ 'sometimes',
+ Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
+ Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_REFINE),
+ ],
'familyName' => [
'bail',
Rule::excludeIf(!is_null($invitation->getUserId()) && $validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
@@ -91,15 +95,13 @@ public function getValidationRules(UserRoleAssignmentInvite $invitation, Validat
'bail',
Rule::excludeIf(!is_null($invitation->getUserId()) && $validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
new ProhibitedIncludingNull(!is_null($invitation->getUserId())),
- Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE]), ['nullable']),
- Rule::requiredIf($validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE),
+ Rule::when(in_array($validationContext, [ValidationContext::VALIDATION_CONTEXT_INVITE, ValidationContext::VALIDATION_CONTEXT_FINALIZE]), ['nullable']),
'sometimes',
'array',
new AllowedKeysRule($allowedLocales),
- new PrimaryLocaleRequired($primaryLocale),
],
'affiliation.*' => [
- 'nullable', // Make optional for other locales
+ 'nullable', // Make optional for all locales
'string',
'max:255',
],
From 17d1297863b023d824504a3f5bc29543762ec3d9 Mon Sep 17 00:00:00 2001
From: Dimitris Efstathiou
Date: Wed, 30 Oct 2024 11:59:11 +0200
Subject: [PATCH 18/26] pkp/pkp-lib#10550 Include active roles to the
validation rule
---
.../invitations/userRoleAssignment/rules/AddUserGroupRule.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/classes/invitation/invitations/userRoleAssignment/rules/AddUserGroupRule.php b/classes/invitation/invitations/userRoleAssignment/rules/AddUserGroupRule.php
index bbc4ad4bd68..b6347eb42a9 100644
--- a/classes/invitation/invitations/userRoleAssignment/rules/AddUserGroupRule.php
+++ b/classes/invitation/invitations/userRoleAssignment/rules/AddUserGroupRule.php
@@ -33,6 +33,7 @@ public function passes($attribute, $value)
if ($user = $this->invitation->getExistingUser()) {
$userUserGroups = UserUserGroup::withUserId($user->getId())
->withUserGroupId($value) // The $value is the userGroupId
+ ->withActive()
->get();
return $userUserGroups->isEmpty(); // Fail if the user does have the group assigned
From e8bdca46737fb77d39a7a041cec5f7526dd07835 Mon Sep 17 00:00:00 2001
From: ipula
Date: Thu, 24 Oct 2024 16:00:29 +0200
Subject: [PATCH 19/26] send and accept invitation views and php integrations
---
.../invitation/AcceptUserDetailsForm.php | 87 +++++
.../forms/invitation/UserDetailsForm.php | 69 ++++
...RoleAssignmentInviteRedirectController.php | 40 ++-
classes/invitation/sections/Email.php | 98 ++++++
classes/invitation/sections/Form.php | 45 +++
classes/invitation/sections/Section.php | 54 +++
classes/invitation/sections/Sections.php | 75 +++++
.../stepTypes/AcceptInvitationStep.php | 212 ++++++++++++
.../stepTypes/InvitationStepTypes.php | 34 ++
.../stepTypes/SendInvitationStep.php | 186 +++++++++++
classes/invitation/steps/Step.php | 73 +++++
js/load.js | 6 +
locale/en/invitation.po | 308 +++++++++++++++++-
locale/en/user.po | 3 +
pages/invitation/InvitationHandler.php | 142 ++++++++
pages/invitation/index.php | 1 +
templates/invitation/acceptInvitation.tpl | 23 ++
templates/invitation/userInvitation.tpl | 25 ++
templates/management/access.tpl | 1 +
19 files changed, 1478 insertions(+), 4 deletions(-)
create mode 100644 classes/components/forms/invitation/AcceptUserDetailsForm.php
create mode 100644 classes/components/forms/invitation/UserDetailsForm.php
create mode 100644 classes/invitation/sections/Email.php
create mode 100644 classes/invitation/sections/Form.php
create mode 100644 classes/invitation/sections/Section.php
create mode 100644 classes/invitation/sections/Sections.php
create mode 100644 classes/invitation/stepTypes/AcceptInvitationStep.php
create mode 100644 classes/invitation/stepTypes/InvitationStepTypes.php
create mode 100644 classes/invitation/stepTypes/SendInvitationStep.php
create mode 100644 classes/invitation/steps/Step.php
create mode 100644 templates/invitation/acceptInvitation.tpl
create mode 100644 templates/invitation/userInvitation.tpl
diff --git a/classes/components/forms/invitation/AcceptUserDetailsForm.php b/classes/components/forms/invitation/AcceptUserDetailsForm.php
new file mode 100644
index 00000000000..532ed843537
--- /dev/null
+++ b/classes/components/forms/invitation/AcceptUserDetailsForm.php
@@ -0,0 +1,87 @@
+action = $action;
+ $this->locales = $locales;
+
+ $countries = [];
+ foreach (Locale::getCountries() as $country) {
+ $countries[] = [
+ 'value' => $country->getAlpha2(),
+ 'label' => $country->getLocalName()
+ ];
+ }
+
+ usort($countries, function ($a, $b) {
+ return strcmp($a['label'], $b['label']);
+ });
+
+ $this->addField(new FieldText('givenName', [
+ 'label' => __('user.givenName'),
+ 'description' => __('acceptInvitation.userDetailsForm.givenName.description'),
+ 'isRequired' => true,
+ 'isMultilingual' => true,
+ 'size' => 'large',
+ 'value' => ''
+ ]))
+ ->addField(new FieldText('familyName', [
+ 'label' => __('user.familyName'),
+ 'description' => __('acceptInvitation.userDetailsForm.familyName.description'),
+ 'isRequired' => false,
+ 'isMultilingual' => true,
+ 'size' => 'large',
+ 'value' => ''
+ ]))
+ ->addField(new FieldText('affiliation', [
+ 'label' => __('user.affiliation'),
+ 'description' => __('acceptInvitation.userDetailsForm.affiliation.description'),
+ 'isMultilingual' => true,
+ 'isRequired' => false,
+ 'size' => 'large',
+
+ ]))
+ ->addField(new FieldSelect('userCountry', [
+ 'label' => __('acceptInvitation.userDetailsForm.countryOfAffiliation.label'),
+ 'description' => __('acceptInvitation.userDetailsForm.countryOfAffiliation.description'),
+ 'options' => $countries,
+ 'isRequired' => true,
+ 'size' => 'large',
+ ]));
+
+ }
+}
diff --git a/classes/components/forms/invitation/UserDetailsForm.php b/classes/components/forms/invitation/UserDetailsForm.php
new file mode 100644
index 00000000000..01306aec5f4
--- /dev/null
+++ b/classes/components/forms/invitation/UserDetailsForm.php
@@ -0,0 +1,69 @@
+action = $action;
+ $this->locales = $locales;
+
+ $this->addField(new FieldText('inviteeEmail', [
+ 'label' => __('user.email'),
+ 'description' => __('invitation.email.description'),
+ 'isRequired' => true,
+ 'size' => 'large',
+ ]))
+ ->addField(new FieldHTML('orcid', [
+ 'label' => __('user.orcid'),
+ 'description' => __('invitation.orcid.description'),
+ 'isRequired' => false,
+ 'size' => 'large',
+ ]))
+ ->addField(new FieldText('givenName', [
+ 'label' => __('user.givenName'),
+ 'description' => __('invitation.givenName.description'),
+ 'isRequired' => false,
+ 'isMultilingual' => true,
+ 'size' => 'large',
+ ]))
+ ->addField(new FieldText('familyName', [
+ 'label' => __('user.familyName'),
+ 'description' => __('invitation.familyName.description'),
+ 'isRequired' => false,
+ 'isMultilingual' => true,
+ 'size' => 'large',
+ ]));
+ }
+}
diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
index c0832538780..07b923a5868 100644
--- a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
+++ b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
@@ -15,9 +15,12 @@
use APP\core\Request;
use APP\template\TemplateManager;
+use PKP\core\PKPApplication;
use PKP\invitation\core\enums\InvitationAction;
+use PKP\invitation\core\enums\InvitationStatus;
use PKP\invitation\core\InvitationActionRedirectController;
use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite;
+use PKP\invitation\stepTypes\AcceptInvitationStep;
class UserRoleAssignmentInviteRedirectController extends InvitationActionRedirectController
{
@@ -29,14 +32,45 @@ public function getInvitation(): UserRoleAssignmentInvite
public function acceptHandle(Request $request): void
{
$templateMgr = TemplateManager::getManager($request);
-
$templateMgr->assign('invitation', $this->invitation);
- $templateMgr->display('frontend/pages/invitations.tpl');
+ $context = $request->getContext();
+ $steps = new AcceptInvitationStep();
+ $templateMgr->setState([
+ 'steps' => $steps->getSteps($this->invitation, $context),
+ 'primaryLocale' => $context->getData('primaryLocale'),
+ 'pageTitle' => __('invitation.wizard.pageTitle'),
+ 'invitationId' => (int)$request->getUserVar('id') ?: null,
+ 'invitationKey' => $request->getUserVar('key') ?: null,
+ 'pageTitleDescription' => __('invitation.wizard.pageTitleDescription'),
+ ]);
+ $templateMgr->assign([
+ 'pageComponent' => 'PageOJS',
+ ]);
+ $templateMgr->display('invitation/acceptInvitation.tpl');
}
public function declineHandle(Request $request): void
{
- return;
+ if ($this->invitation->getStatus() !== InvitationStatus::PENDING) {
+ $request->getDispatcher()->handle404();
+ }
+
+ $context = $request->getContext();
+
+ $url = PKPApplication::get()->getDispatcher()->url(
+ PKPApplication::get()->getRequest(),
+ PKPApplication::ROUTE_PAGE,
+ $context->getData('urlPath'),
+ 'login',
+ null,
+ null,
+ [
+ ]
+ );
+
+ $this->getInvitation()->decline();
+
+ $request->redirectUrl($url);
}
public function preRedirectActions(InvitationAction $action)
diff --git a/classes/invitation/sections/Email.php b/classes/invitation/sections/Email.php
new file mode 100644
index 00000000000..8e80d42a2bf
--- /dev/null
+++ b/classes/invitation/sections/Email.php
@@ -0,0 +1,98 @@
+ $recipients One or more User objects who are the recipients of this email
+ * @param Mailable $mailable The mailable that will be used to send this email
+ *
+ * @throws Exception
+ */
+ public function __construct(string $id, string $name, string $description, array $recipients, Mailable $mailable, array $locales)
+ {
+ parent::__construct($id, $name, $description);
+ $this->locales = $locales;
+ $this->mailable = $mailable;
+ $this->recipients = $recipients;
+ }
+
+ public function getState(): stdClass
+ {
+ $config = parent::getState();
+ $config->canChangeRecipients = false;
+ $config->canSkip = false;
+ $config->emailTemplates = $this->getEmailTemplates();
+ $config->initialTemplateKey = $this->mailable::getEmailTemplateKey();
+ $config->recipientOptions = $this->getRecipientOptions();
+ $config->anonymousRecipients = $this->anonymousRecipients;
+ $config->variables = [];
+ $config->locale = Locale::getLocale();
+ $config->locales = [];
+ return $config;
+ }
+
+ protected function getRecipientOptions(): array
+ {
+ $recipientOptions = [];
+ foreach ($this->recipients as $user) {
+ $names = [];
+ foreach ($this->locales as $locale) {
+ $names[$locale] = $user->getFullName(true, false, $locale);
+ }
+ $recipientOptions[] = [
+ 'value' => $user->getId(),
+ 'label' => $names,
+ ];
+ }
+ return $recipientOptions;
+ }
+
+ protected function getEmailTemplates(): array
+ {
+ $request = Application::get()->getRequest();
+ $context = $request->getContext();
+
+ $emailTemplates = collect();
+ if ($this->mailable::getEmailTemplateKey()) {
+ $emailTemplate = Repo::emailTemplate()->getByKey($context->getId(), $this->mailable::getEmailTemplateKey());
+ if ($emailTemplate) {
+ $emailTemplates->add($emailTemplate);
+ }
+ Repo::emailTemplate()
+ ->getCollector($context->getId())
+ ->alternateTo([$this->mailable::getEmailTemplateKey()])
+ ->getMany()
+ ->each(fn (EmailTemplate $e) => $emailTemplates->add($e));
+ }
+
+ return Repo::emailTemplate()->getSchemaMap()->mapMany($emailTemplates)->toArray();
+ }
+}
diff --git a/classes/invitation/sections/Form.php b/classes/invitation/sections/Form.php
new file mode 100644
index 00000000000..c62ba7fb3db
--- /dev/null
+++ b/classes/invitation/sections/Form.php
@@ -0,0 +1,45 @@
+form = $form;
+ }
+
+ public function getState(): stdClass
+ {
+ $config = parent::getState();
+ foreach ($this->form->getConfig() as $key => $value) {
+ $config->$key = $value;
+ }
+ unset($config->pages[0]['submitButton']);
+
+ return $config;
+ }
+}
diff --git a/classes/invitation/sections/Section.php b/classes/invitation/sections/Section.php
new file mode 100644
index 00000000000..89fe3e96d42
--- /dev/null
+++ b/classes/invitation/sections/Section.php
@@ -0,0 +1,54 @@
+id = $id;
+ $this->name = $name;
+ $this->description = $description;
+ if (!isset($this->type)) {
+ throw new Exception('Decision workflow step created without specifying a type.');
+ }
+ }
+
+ /**
+ * Compile initial state data to pass to the frontend
+ */
+ public function getState(): stdClass
+ {
+ $config = new stdClass();
+ $config->id = $this->id;
+ $config->type = $this->type;
+ $config->name = $this->name;
+ $config->description = $this->description;
+ $config->errors = new stdClass();
+
+ return $config;
+ }
+}
diff --git a/classes/invitation/sections/Sections.php b/classes/invitation/sections/Sections.php
new file mode 100644
index 00000000000..abce3d0f69b
--- /dev/null
+++ b/classes/invitation/sections/Sections.php
@@ -0,0 +1,75 @@
+id = $id;
+ $this->name = $name;
+ $this->description = $description;
+ $this->sectionComponent = $sectionComponent;
+ $this->type = $type;
+ }
+ /**
+ * Add a step to the invitation
+ */
+ public function addSection($section, $props): void
+ {
+ if(is_null($section)) {
+ $this->sections[] = $section;
+ } else {
+ $this->sections[$section->id] = $section;
+ }
+ $this->props = $props;
+ }
+
+ /**
+ * get section states
+ */
+ public function getState(): array
+ {
+ $state = [];
+ foreach ($this->sections as $section) {
+ if(is_null($section)) {
+ $props = [
+ ...$this->props
+ ];
+ } else {
+ $props = [
+ ...$this->props,
+ $section->type => $section->getState(),
+ ];
+ }
+ $state[] = [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'description' => $this->description,
+ 'sectionComponent' => $this->sectionComponent,
+ 'props' => $props,
+ ];
+ }
+ return $state;
+ }
+}
diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php
new file mode 100644
index 00000000000..59e7a8d1de6
--- /dev/null
+++ b/classes/invitation/stepTypes/AcceptInvitationStep.php
@@ -0,0 +1,212 @@
+invitationModel->userId) {
+ case !null:
+ $user = Repo::user()->get($invitation->invitationModel->userId);
+ if(!$user->getData('orcidAccessToken')) {
+ $steps[] = $this->verifyOrcidStep();
+ $steps[] = $this->acceptInvitationReviewStep($context);
+ }
+ break;
+ default:
+ $steps[] = $this->verifyOrcidStep();
+ $steps[] = $this->userAccountDetailsStep();
+ $steps[] = $this->userDetailsStep($context);
+ $steps[] = $this->acceptInvitationReviewStep($context);
+ }
+ return $steps;
+ }
+
+ /**
+ * user orcid verification step
+ */
+ private function verifyOrcidStep(): \stdClass
+ {
+ $sections = new Sections(
+ 'userVerifyOrcid',
+ __('acceptInvitation.verifyOrcid.stepName'),
+ __('userInvitation.searchUser.stepDescription'),
+ 'popup',
+ 'AcceptInvitationVerifyOrcid'
+ );
+ $sections->addSection(
+ null,
+ [
+ 'validateFields' => []
+ ]
+ );
+ $step = new Step(
+ 'verifyOrcid',
+ __('acceptInvitation.verifyOrcid.stepName'),
+ __('acceptInvitation.verifyOrcid.stepDescription'),
+ __('acceptInvitation.verifyOrcid.stepLabel'),
+ __('userInvitation.verifyOrcid.nextButtonLabel'),
+ 'popup'
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * user account details step
+ */
+ private function userAccountDetailsStep(): \stdClass
+ {
+ $sections = new Sections(
+ 'userCreateForm',
+ __('acceptInvitation.accountDetails.stepName'),
+ __('userInvitation.accountDetails.stepDescription'),
+ 'form',
+ 'AcceptInvitationUserAccountDetails'
+ );
+ $sections->addSection(
+ null,
+ [
+ 'validateFields' => [
+ 'username',
+ 'password',
+ 'privacyStatement'
+ ]
+ ]
+ );
+ $step = new Step(
+ 'userCreate',
+ __('acceptInvitation.accountDetails.stepName'),
+ __('acceptInvitation.accountDetails.stepDescription'),
+ __('acceptInvitation.accountDetails.stepLabel'),
+ __('acceptInvitation.accountDetails.nextButtonLabel'),
+ 'form'
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * user details form step
+ *
+ * @throws \Exception
+ */
+ private function userDetailsStep(Context $context): \stdClass
+ {
+ $sections = new Sections(
+ 'userCreateForm',
+ __('acceptInvitation.accountDetails.stepName'),
+ __('userInvitation.accountDetails.stepDescription'),
+ 'form',
+ 'AcceptInvitationUserDetailsForms'
+ );
+ $sections->addSection(
+ new Form(
+ 'userDetails',
+ __('acceptInvitation.userDetails.form.name'),
+ __('acceptInvitation.userDetails.form.description'),
+ new AcceptUserDetailsForm('accept', $this->getFormLocals($context)),
+ ),
+ [
+ 'validateFields' => [
+ 'affiliation',
+ 'givenName',
+ 'familyName',
+ 'userCountry',
+ ]
+ ]
+ );
+ $step = new Step(
+ 'userDetails',
+ __('acceptInvitation.userDetails.stepName'),
+ __('acceptInvitation.userDetails.stepDescription'),
+ __('acceptInvitation.userDetails.stepLabel'),
+ __('acceptInvitation.userDetails.nextButtonLabel'),
+ 'form'
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * review details and accept invitation step
+ *
+ * @throws \Exception
+ */
+ private function acceptInvitationReviewStep(Context $context): \stdClass
+ {
+ $sections = new Sections(
+ 'userCreateRoles',
+ '',
+ '',
+ 'table',
+ 'AcceptInvitationReview'
+ );
+ $sections->addSection(
+ new Form(
+ 'userDetails',
+ __('acceptInvitation.userDetails.form.name'),
+ __('acceptInvitation.userDetails.form.description'),
+ new AcceptUserDetailsForm('accept', $this->getFormLocals($context)),
+ ),
+ [
+ 'validateFields' => [
+
+ ]
+ ]
+ );
+ $step = new Step(
+ 'userCreateReview',
+ __('acceptInvitation.detailsReview.stepName'),
+ __('acceptInvitation.detailsReview.stepDescription'),
+ __('acceptInvitation.detailsReview.stepLabel'),
+ __('acceptInvitation.detailsReview.nextButtonLabel'),
+ 'review'
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * @param Context $context
+ * @return array
+ */
+ private function getFormLocals(Context $context): array
+ {
+ $localeNames = $context->getSupportedFormLocaleNames();
+ $locales = [];
+ foreach ($localeNames as $key => $name) {
+ $locales[] = [
+ 'key' => $key,
+ 'label' => $name,
+ ];
+ }
+ return $locales;
+ }
+}
diff --git a/classes/invitation/stepTypes/InvitationStepTypes.php b/classes/invitation/stepTypes/InvitationStepTypes.php
new file mode 100644
index 00000000000..6bb90f28feb
--- /dev/null
+++ b/classes/invitation/stepTypes/InvitationStepTypes.php
@@ -0,0 +1,34 @@
+invitationSearchUser();
+ }
+ $steps[] = $this->invitationDetailsForm($context);
+ $steps[] = $this->invitationInvitedEmail($context);
+ return $steps;
+ }
+
+ /**
+ * create search user section
+ */
+ private function invitationSearchUser(): stdClass
+ {
+ $sections = new Sections(
+ 'searchUserForm',
+ __('userInvitation.searchUser.stepName'),
+ __('userInvitation.searchUser.stepDescription'),
+ 'form',
+ 'UserInvitationSearchFormStep',
+ true
+ );
+ $sections->addSection(
+ null,
+ [
+ 'validateFields' => []
+ ]
+ );
+ $step = new Step(
+ 'searchUser',
+ __('userInvitation.searchUser.stepName'),
+ __('userInvitation.searchUser.stepDescription'),
+ __('userInvitation.searchUser.stepLabel'),
+ __('userInvitation.searchUser.nextButtonLabel'),
+ 'emptySection',
+ true
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * create user details form section
+ *
+ * @throws Exception
+ */
+ private function invitationDetailsForm(Context $context): stdClass
+ {
+ $localeNames = $context->getSupportedFormLocaleNames();
+ $locales = [];
+ foreach ($localeNames as $key => $name) {
+ $locales[] = [
+ 'key' => $key,
+ 'label' => $name,
+ ];
+ }
+ $sections = new Sections(
+ 'userDetails',
+ __('userInvitation.enterDetails.stepName'),
+ __('userInvitation.enterDetails.stepDescription'),
+ 'form',
+ 'UserInvitationDetailsFormStep'
+ );
+ $sections->addSection(
+ new Form(
+ 'userDetails',
+ __('userInvitation.enterDetails.stepName'),
+ __('userInvitation.enterDetails.stepDescription'),
+ new UserDetailsForm('users', $locales, $context),
+ ),
+ [
+ 'validateFields' => [],
+ 'userGroups' => $this->getAllUserGroup($context)
+ ]
+ );
+ $step = new Step(
+ 'userDetails',
+ __('userInvitation.enterDetails.stepName'),
+ __('userInvitation.enterDetails.stepDescription'),
+ __('userInvitation.enterDetails.stepLabel'),
+ __('userInvitation.enterDetails.nextButtonLabel'),
+ 'form'
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * create email composer for send invite
+ *
+ * @throws Exception
+ */
+ private function invitationInvitedEmail(Context $context): stdClass
+ {
+ $sections = new Sections(
+ 'userInvitedEmail',
+ __('userInvitation.sendMail.stepLabel'),
+ __('userInvitation.sendMail.stepName'),
+ 'email',
+ 'UserInvitationEmailComposerStep'
+ );
+ $fakeInvitation = $this->getFakeInvitation();
+ $mailable = new UserRoleAssignmentInvitationNotify($context, $fakeInvitation);
+ $sections->addSection(
+ new Email(
+ 'userInvited',
+ __('userInvitation.sendMail.stepName'),
+ __('userInvitation.sendMail.stepDescription'),
+ [],
+ $mailable
+ ->sender(Application::get()->getRequest()->getUser())
+ ->cc('')
+ ->bcc(''),
+ $context->getSupportedFormLocales(),
+ ),
+ [
+ 'validateFields' => []
+ ]
+ );
+ $step = new Step(
+ 'userInvited',
+ __('userInvitation.sendMail.stepName'),
+ __('userInvitation.sendMail.stepDescription'),
+ __('userInvitation.sendMail.stepLabel'),
+ __('userInvitation.sendMail.nextButtonLabel'),
+ 'email'
+ );
+ $step->addSectionToStep($sections->getState());
+ return $step->getState();
+ }
+
+ /**
+ * get all user groups
+ */
+ private function getAllUserGroup(Context $context): array
+ {
+ $allUserGroups = [];
+ $userGroups = Repo::userGroup()->getCollector()
+ ->filterByContextIds([$context->getId()])
+ ->getMany();
+ foreach ($userGroups as $userGroup) {
+ $allUserGroups[] = [
+ 'value' => (int) $userGroup->getId(),
+ 'label' => $userGroup->getLocalizedName(),
+ 'disabled' => false
+ ];
+ }
+ return $allUserGroups;
+ }
+}
diff --git a/classes/invitation/steps/Step.php b/classes/invitation/steps/Step.php
new file mode 100644
index 00000000000..adf35516516
--- /dev/null
+++ b/classes/invitation/steps/Step.php
@@ -0,0 +1,73 @@
+id = $id;
+ $this->name = $name;
+ $this->description = $description;
+ $this->stepLabel = $stepLabel;
+ $this->nextButtonLabel = $nextButtonLabel;
+ $this->type = $type;
+ $this->skipInvitationUpdate = $skipInvitationUpdate;
+ }
+
+ /**
+ * Compile initial state data to pass to the frontend
+ */
+ public function getState(): stdClass
+ {
+ $config = new stdClass();
+ $config->id = $this->id;
+ $config->name = $this->name;
+ $config->description = $this->description;
+ $config->nextButtonLabel = $this->nextButtonLabel;
+ $config->skipInvitationUpdate = $this->skipInvitationUpdate;
+ $config->type = $this->type;
+ $config->stepLabel = $this->stepLabel;
+ $config->sections = $this->sections;
+ return $config;
+ }
+
+ /**
+ * Add a step to the workflow
+ */
+ public function addSectionToStep($sections): void
+ {
+ $this->sections = $sections;
+ }
+}
diff --git a/js/load.js b/js/load.js
index d82c54741b6..1ee1f943881 100644
--- a/js/load.js
+++ b/js/load.js
@@ -106,6 +106,9 @@ import FieldSlider from '@/components/Form/fields/FieldSlider.vue';
// Panel components from UI Library
import ListPanel from '@/components/ListPanel/ListPanel.vue';
+// Manager components
+import UserInvitationManager from '@/managers/UserInvitationManager/UserInvitationManager.vue';
+
// Helper for initializing and tracking Vue controllers
import VueRegistry from './classes/VueRegistry.js';
@@ -216,6 +219,9 @@ VueRegistry.registerComponent('field-pub-id', FieldPubId);
// Register ListPanel
VueRegistry.registerComponent('PkpListPanel', ListPanel);
+// Register Invitation Manager
+VueRegistry.registerComponent('UserInvitationManager', UserInvitationManager);
+
const pinia = createPinia();
function pkpCreateVueApp(createAppArgs) {
diff --git a/locale/en/invitation.po b/locale/en/invitation.po
index 402116a7861..e8d31c12a45 100644
--- a/locale/en/invitation.po
+++ b/locale/en/invitation.po
@@ -101,4 +101,310 @@ msgid "invitation.validation.error.propertyProhibited"
msgstr "The :attribute field is prohibited"
msgid "invitation.userRoleAssignment.validation.error.multilingual.primaryLocaleRequired"
-msgstr "A value for locale '{$primaryLocale}' is required"
\ No newline at end of file
+msgstr "A value for locale '{$primaryLocale}' is required"
+
+msgid "invitation.step"
+msgstr "STEP"
+
+msgid "invitation.header"
+msgstr "Invitations"
+
+msgid "invitation.inviteToRole.btn"
+msgstr "Invite to a role"
+
+msgid "invitation.wizard.pageTitle"
+msgstr "Invite user to take a role"
+
+msgid "invitation.wizard.pageTitleDescription"
+msgstr "You are inviting a user to take a role in OJS along with appearing in the journal masthead"
+
+msgid "userInvitation.enterDetailsLabel"
+msgstr "Enter details"
+
+msgid "userInvitation.reviewAndInviteLabel"
+msgstr "Review & invite for roles"
+
+msgid "userInvitation.searchUser.stepName"
+msgstr "Search User"
+
+msgid "userInvitation.searchUser.stepLabel"
+msgstr "{$step} - Search User"
+
+msgid "userInvitation.searchUser.nextButtonLabel"
+msgstr "Search User"
+
+msgid "userInvitation.searchUser.stepDescription"
+msgstr "Search for the user using their email address, username or ORCID ID. Enter at least one details to get started. If user does not exist, ypu can invite them to take up roles and be a part of your journal. If the user already exist in the system, you can view user information and invite to take a additional roles."
+
+msgid "userInvitation.emailField.description"
+msgstr "e.g. aeinstein@example.com"
+
+msgid "userInvitation.usernameField.description"
+msgstr "e.g. mickeymouse"
+
+msgid "userInvitation.orcidField.description"
+msgstr "e.g. 0000-0000-0000-0000"
+
+msgid "userInvitation.enterDetails.stepName"
+msgstr "Enter details"
+
+msgid "userInvitation.enterDetails.stepLabel"
+msgstr "{$step} - Enter details and invite for roles"
+
+msgid "userInvitation.enterDetails.stepDescription"
+msgstr "You can invite them to take up a role in OJS"
+
+msgid "userInvitation.enterDetails.nextButtonLabel"
+msgstr "Save And Continue"
+
+msgid "invitation.role.selectRole"
+msgstr "Select a new role"
+
+msgid "invitation.role.dateStart"
+msgstr "Start Date"
+
+msgid "invitation.role.dateEnd"
+msgstr "End Date"
+
+msgid "invitation.role.masthead"
+msgstr "Journal Masthead"
+
+msgid "invitation.role.addRole.button"
+msgstr "Add Another Role"
+
+msgid "userInvitation.roleTable.role"
+msgstr "Role"
+
+msgid "userInvitation.roleTable.startDate"
+msgstr "Start Date"
+
+msgid "userInvitation.roleTable.endDate"
+msgstr "End Date"
+
+msgid "userInvitation.roleTable.journalMasthead"
+msgstr "Journal Masthead"
+
+msgid "userInvitation.sendMail.stepName"
+msgstr "Review & invite for roles"
+
+msgid "userInvitation.sendMail.nextButtonLabel"
+msgstr "Invite user to the role"
+
+msgid "userInvitation.sendMail.stepDescription"
+msgstr "Send the user an email to let them know about the invitation, next steps, journal GDPR polices and ORCiD verification"
+
+msgid "userInvitation.sendMail.stepLabel"
+msgstr "{$step} - Modify email shared with the user"
+
+msgid "userInvitation.modal.title"
+msgstr "Invitation Sent"
+
+msgid "userInvitation.modal.message"
+msgstr "{$email} has been invited to new role in OJS.You can be updated about users on the User and Roles page, your ojs notification and/ or your email"
+
+msgid "userInvitation.modal.button"
+msgstr "View All Users"
+
+msgid "invitation.role.removeRole.button"
+msgstr "Remove Role"
+
+msgid "invitation.email.description"
+msgstr "e.g. aeinstein@example.com"
+
+msgid "invitation.orcid.description"
+msgstr "On accepting the invite, the user will be redirected to ORCID to verify their account, if they wish to."
+
+msgid "invitation.givenName.description"
+msgstr "If you know the given name of the user, you can enter the information. However, this information can be changed by the user"
+
+msgid "invitation.familyName.description"
+msgstr "If you know the family name of the user, you can enter the information. However, this information can be changed by the user"
+
+msgid "acceptInvitation.verifyOrcid.stepName"
+msgstr "Verify ORCID iD"
+
+msgid "acceptInvitation.verifyOrcid.stepLabel"
+msgstr "{$step} - Verify ORCID iD"
+
+msgid "acceptInvitation.verifyOrcid.stepDescription"
+msgstr "You can choose to verify your ORCID iD ok skip it. If you chose to skip it now, You can verify your ORCID iD from your profile section in OJS later"
+
+msgid "acceptInvitation.verifyOrcid.nextButtonLabel"
+msgstr "Save and continue"
+
+msgid "acceptInvitation.accountDetails.stepName"
+msgstr "Create OJS account"
+
+msgid "acceptInvitation.accountDetails.stepLabel"
+msgstr "{$step} - Create OJS account"
+
+msgid "acceptInvitation.accountDetails.stepDescription"
+msgstr "To get started with OJS and accept the new role, you will need to create an account with us. For this purpose please enter a username and password."
+
+msgid "acceptInvitation.accountDetails.nextButtonLabel"
+msgstr "Save and continue"
+
+msgid "acceptInvitation.userDetails.stepName"
+msgstr "Enter details"
+
+msgid "acceptInvitation.userDetails.stepLabel"
+msgstr "{$step} - Enter details"
+
+msgid "acceptInvitation.userDetails.stepDescription"
+msgstr "Enter your details like email ID, affiliation ect. As per the GDPR compliance, this information can only modified by you. You can also choose if you want this information to be visible on your profile to the editor."
+
+msgid "acceptInvitation.userDetails.nextButtonLabel"
+msgstr "Save and continue"
+
+msgid "acceptInvitation.userDetails.form.name"
+msgstr "Accept invitation user details form"
+
+msgid "acceptInvitation.userDetails.form.description"
+msgstr "Please provide the following details to help us to manage your account"
+
+msgid "acceptInvitation.detailsReview.stepName"
+msgstr "Review & create account"
+
+msgid "acceptInvitation.detailsReview.stepLabel"
+msgstr "{$step} - Review & create account"
+
+msgid "acceptInvitation.detailsReview.stepDescription"
+msgstr "Review details to start your new roles in OJS"
+
+msgid "acceptInvitation.detailsReview.nextButtonLabel"
+msgstr "Accept And Continue to OJS"
+
+msgid "acceptInvitation.skipVerifyOrcid"
+msgstr "Skip ORCID verification"
+
+msgid "acceptInvitation.verifyOrcid"
+msgstr "Verify ORCID iD"
+
+msgid "acceptInvitation.usernameField.description"
+msgstr "It should be 10 characters long and could be a combination of uppercase letters, lowercase letters or numbers"
+
+msgid "acceptInvitation.passwordField.description"
+msgstr "It should be 12 characters long and should be a combination of uppercase letters, lowercase letters, numbers and symbols"
+
+msgid "acceptInvitation.privacyStatement.label"
+msgstr "Yes, I agree to have my data collected and stored according to the"
+
+msgid "acceptInvitation.privacyStatement.btn"
+msgstr "Privacy Statement"
+
+msgid "acceptInvitation.userDetailsForm.givenName.description"
+msgstr "Also known as a forename or the first name, it is tha part of a personal name that identifies a preson"
+
+msgid "acceptInvitation.userDetailsForm.familyName.description"
+msgstr "A surname, family name, or last name is the mostly hereditary portion of one's personal name that indicates one's family"
+
+msgid "acceptInvitation.userDetailsForm.affiliation.description"
+msgstr "This is the institute you are affiliated with"
+
+msgid "acceptInvitation.userDetailsForm.countryOfAffiliation.description"
+msgstr "This is a country in which the institute you are affiliated with is situated"
+
+msgid "acceptInvitation.userDetailsForm.countryOfAffiliation.label"
+msgstr "Country of affiliation"
+
+msgid "acceptInvitation.review.accountDetails"
+msgstr "Account Details"
+
+msgid "acceptInvitation.review.userDetails"
+msgstr "User Details"
+
+msgid "invitation.orcid.acceptInvitation.message"
+msgstr "Not verified. You can verify your ORCID iD from your profile section in OJS"
+
+msgid "acceptInvitation.modal.title"
+msgstr "You've been assigned a new role in OJS"
+
+msgid "acceptInvitation.modal.message"
+msgstr "Congratulations on your new role in OJS! You might now have access to new options. If you need assistance navigating the system, please click on the “Help” buttons throughout the interface for guidance"
+
+msgid "acceptInvitation.modal.button"
+msgstr "View All Submissions"
+
+msgid "invitation.tableHeader.name"
+msgstr "Name"
+
+msgid "invitation.searchForm.emptyError"
+msgstr "At least provide one search criteria."
+
+msgid "invitation.wizard.viewPageTitleDescription"
+msgstr "You are viewing {$name}'s user details"
+
+msgid "invitation.reviewerAccess.validation.error.reviewAssignmentId.notExisting"
+msgstr "The id {reviewAssignmentId} does not correspond to a valid review assignment"
+
+msgid "invitation.api.error.invitationCantBeCanceled"
+msgstr "This invitation can't be cancelled"
+
+msgid "invitation.api.error.initialization.noUserIdAndEmailTogether"
+msgstr "You cannot provide both email and userId together."
+
+msgid "invitation.userRoleAssignment.error.update.prohibitedForExistingUser"
+msgstr "The attribute is not allowed to be access for existing users"
+
+msgid "invitation.userRoleAssignment.error.update.prohibitedForNonExistingUser"
+msgstr "The attribute is not allowed to be access for non existing users"
+
+msgid "invitation.userRoleAssignment.userGroup.startDate.mustBeAfterToday"
+msgstr "This attribute must have a value equal or after today"
+
+msgid "invitation.validation.error.propertyProhibited"
+msgstr "The :attribute field is prohibited"
+
+msgid "invitation.cancelInvite.actionName"
+msgstr "Cancel Invite"
+
+msgid "invitation.cancelInvite.title"
+msgstr "Cancel Invitation"
+
+msgid "invitation.cancelInvite.message"
+msgstr "Cancel the invitation sent to {$givenName} {$familyName} will deactivate acceptance link sent via email. Here are the invitation details: "
+
+msgid "invitation.masthead.show"
+msgstr "Appear on the masthead"
+
+msgid "invitation.masthead.hidden"
+msgstr "Does not appear on the masthead"
+
+msgid "invitation.role.modifyRole.button"
+msgstr "Modify Role"
+
+msgid "invitation.management.options"
+msgstr "Invitation management options"
+
+msgid "userInvitation.cancel.message"
+msgstr "Are you sure want to cancel this invitation ?"
+
+msgid "userInvitation.cancel.keepWorking"
+msgstr "Keep Working"
+
+msgid "userInvitation.status.invited"
+msgstr "Invited {$date}"
+
+msgid "userInvitation.search.userNotFound"
+msgstr "The user does not have a role in this journal"
+
+msgid "userInvitation.search.userFound"
+msgstr "The user already exists in the journal"
+
+msgid "userInvitation.edit.title"
+msgstr "Edit Invitation"
+
+msgid "userInvitation.edit.message"
+msgstr "If you edit the existing invitation or add a new role, the current invitation will be canceled and, a new one will be sent. Are you sure you want to proceed?"
+
+msgid "validation.after_or_equal"
+msgstr "Start date should be greater than or equal to today"
+
+msgid "invitation.removeRoles"
+msgstr "User Removed From Role"
+
+msgid "acceptInvitation.privacyStatement.validation"
+msgstr "Please confirm that you have read and agree privacy statement"
+
+msgid "acceptInvitation.cancel.message"
+msgstr "Are you sure want to cancel accepting invitation ?"
diff --git a/locale/en/user.po b/locale/en/user.po
index 29721f1288b..0bd2b34d368 100644
--- a/locale/en/user.po
+++ b/locale/en/user.po
@@ -788,3 +788,6 @@ msgstr "Are you sure you want to remove this ORCID?"
msgid "orcid.field.unverified.shouldRequest"
msgstr "This ORCID has not been verified. Please remove this unverified ORCID and request verification from the user/author directly."
+
+msgid "user.removeRole.message"
+msgstr "Are you sure want remove this role permanently ?"
diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php
index 9874438dee5..cdb529b7308 100644
--- a/pages/invitation/InvitationHandler.php
+++ b/pages/invitation/InvitationHandler.php
@@ -20,11 +20,16 @@
use APP\core\Request;
use APP\facades\Repo;
use APP\handler\Handler;
+use APP\template\TemplateManager;
+use PKP\core\PKPApplication;
+use PKP\facades\Locale;
use PKP\invitation\core\enums\InvitationAction;
use PKP\invitation\core\Invitation;
+use PKP\invitation\stepTypes\SendInvitationStep;
class InvitationHandler extends Handler
{
+ public $_isBackendPage = true;
public const REPLY_PAGE = 'invitation';
public const REPLY_OP_ACCEPT = 'accept';
public const REPLY_OP_DECLINE = 'decline';
@@ -34,6 +39,7 @@ class InvitationHandler extends Handler
*/
public function accept(array $args, Request $request): void
{
+ $this->setupTemplate($request);
$invitation = $this->getInvitationByKey($request);
$invitationHandler = $invitation->getInvitationActionRedirectController();
$invitationHandler->preRedirectActions(InvitationAction::ACCEPT);
@@ -62,7 +68,17 @@ private function getInvitationByKey(Request $request): Invitation
if (is_null($invitation)) {
$request->getDispatcher()->handle404();
}
+ return $invitation;
+ }
+
+ private function getInvitationById(Request $request, $id): Invitation
+ {
+ $invitation = Repo::invitation()
+ ->getById($id);
+ if (is_null($invitation)) {
+ $request->getDispatcher()->handle404('The link is deactivated as the invitation was cancelled');
+ }
return $invitation;
}
@@ -92,4 +108,130 @@ public static function getActionUrl(InvitationAction $action, Invitation $invita
]
);
}
+
+ public function invite($args, $request): void
+ {
+ $invitationMode = 'create';
+ $invitationPayload = [
+ 'userId' => null,
+ 'inviteeEmail' => '',
+ 'orcid' => '',
+ 'givenName' => '',
+ 'familyName' => '',
+ 'orcidValidation' => false,
+ 'userGroupsToAdd' => [
+ [
+ 'userGroupId' => null,
+ 'dateStart' => null,
+ 'dateEnd' => null,
+ 'masthead' => null,
+ ]
+ ],
+ 'currentUserGroups' => [],
+ 'userGroupsToRemove' => [],
+ 'emailComposer' => [
+ 'body' => '',
+ 'subject' => '',
+ ]
+ ];
+ $invitation = null;
+ $user = null;
+ if(!empty($args)) {
+ $invitation = $this->getInvitationById($request, $args[0]);
+ $payload = $invitation->getPayload()->toArray();
+ $invitationModel = $invitation->invitationModel->toArray();
+
+ $invitationMode = 'edit';
+ if($invitationModel['userId']){
+ $user = Repo::user()->get($invitationModel['userId']);
+ }
+ $invitationPayload['userId'] = $invitationModel['userId'];
+ $invitationPayload['inviteeEmail'] = $invitationModel['email'] ?: $user->getEmail();
+ $invitationPayload['orcid'] = $payload['orcid']; //$reviewer->getData('orcidAccessToken')
+ $invitationPayload['givenName'] = $user ? $user->getGivenName(null) : $payload['givenName'];
+ $invitationPayload['familyName'] = $user ? $user->getFamilyName(null) : $payload['familyName'];
+ $invitationPayload['affiliation'] = $user ? $user->getAffiliation(null) : $payload['affiliation'];
+ $invitationPayload['country'] = $user ? $user->getCountry() : $payload['userCountry'];
+ $invitationPayload['userGroupsToAdd'] = $payload['userGroupsToAdd'];
+ $invitationPayload['currentUserGroups'] = !$invitationModel['userId'] ? [] : $this->getUserUserGroups($invitationModel['userId']);
+ $invitationPayload['userGroupsToRemove'] = !$payload['userGroupsToRemove'] ? null : $payload['userGroupsToRemove'];
+ $invitationPayload['emailComposer'] = [
+ 'emailBody'=>$payload['emailBody'],
+ 'emailSubject'=>$payload['emailSubject'],
+ ];
+ }
+ $templateMgr = TemplateManager::getManager($request);
+ $breadcrumbs = $templateMgr->getTemplateVars('breadcrumbs');
+ $this->setupTemplate($request);
+ $context = $request->getContext();
+ $breadcrumbs[] = [
+ 'id' => 'contexts',
+ 'name' => __('navigation.access'),
+ 'url' => $request
+ ->getDispatcher()
+ ->url(
+ $request,
+ PKPApplication::ROUTE_PAGE,
+ $request->getContext()->getPath(),
+ 'management',
+ 'settings',
+ )
+ ];
+ $breadcrumbs[] = [
+ 'id' => 'invitationWizard',
+ 'name' => __('invitation.wizard.pageTitle'),
+ ];
+ $steps = new SendInvitationStep();
+ $templateMgr->setState([
+ 'steps' => $steps->getSteps($invitation, $context),
+ 'emailTemplatesApiUrl' => $request
+ ->getDispatcher()
+ ->url(
+ $request,
+ Application::ROUTE_API,
+ $context->getData('urlPath'),
+ 'emailTemplates'
+ ),
+ 'primaryLocale' => $context->getData('primaryLocale'),
+ 'invitationType' => 'userRoleAssignment',
+ 'invitationPayload' => $invitationPayload,
+ 'invitationMode' => $invitationMode,
+ 'pageTitle' => $invitation ?
+ (
+ $invitationPayload['givenName'][Locale::getLocale()] . ' '
+ . $invitationPayload['familyName'][Locale::getLocale()])
+ : __('invitation.wizard.pageTitle'),
+ 'pageTitleDescription' => $invitation ?
+ __(
+ 'invitation.wizard.viewPageTitleDescription',
+ ['name' => $invitationPayload['givenName'][Locale::getLocale()]]
+ )
+ : __('invitation.wizard.pageTitleDescription'),
+ ]);
+ $templateMgr->assign([
+ 'pageComponent' => 'PageOJS',
+ 'breadcrumbs' => $breadcrumbs,
+ 'pageWidth' => TemplateManager::PAGE_WIDTH_FULL,
+ ]);
+ $templateMgr->display('/invitation/userInvitation.tpl');
+ }
+
+ private function getUserUserGroups($id): array
+ {
+ $output = [];
+ $userGroups = Repo::userGroup()->userUserGroups($id);
+ foreach ($userGroups as $userGroup) {
+ $output[] = [
+ 'id' => (int) $userGroup->getId(),
+ 'name' => $userGroup->getName(null),
+ 'abbrev' => $userGroup->getAbbrev(null),
+ 'roleId' => (int) $userGroup->getRoleId(),
+ 'showTitle' => (bool) $userGroup->getShowTitle(),
+ 'permitSelfRegistration' => (bool) $userGroup->getPermitSelfRegistration(),
+ 'permitMetadataEdit' => (bool) $userGroup->getPermitMetadataEdit(),
+ 'recommendOnly' => (bool) $userGroup->getRecommendOnly(),
+ ];
+ }
+ return $output;
+ }
}
diff --git a/pages/invitation/index.php b/pages/invitation/index.php
index cbe585b1269..d9d964fa01f 100644
--- a/pages/invitation/index.php
+++ b/pages/invitation/index.php
@@ -16,5 +16,6 @@
switch ($op) {
case 'decline':
case 'accept':
+ case 'invite':
return new PKP\pages\invitation\InvitationHandler();
}
diff --git a/templates/invitation/acceptInvitation.tpl b/templates/invitation/acceptInvitation.tpl
new file mode 100644
index 00000000000..19e2341e217
--- /dev/null
+++ b/templates/invitation/acceptInvitation.tpl
@@ -0,0 +1,23 @@
+
+{/block}
diff --git a/templates/invitation/userInvitation.tpl b/templates/invitation/userInvitation.tpl
new file mode 100644
index 00000000000..e28201ece18
--- /dev/null
+++ b/templates/invitation/userInvitation.tpl
@@ -0,0 +1,25 @@
+?php
+{**
+ * templates/management/userInvitation.tpl
+ *
+ * Copyright (c) 2014-2024 Simon Fraser University
+ * Copyright (c) 2003-2024 John Willinsky
+ * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
+ *
+ * @brief show create user invitation page to the users.
+ *
+ * @hook Template::Settings::access []
+ *}
+{extends file="layouts/backend.tpl"}
+{block name="page"}
+
+{/block}
diff --git a/templates/management/access.tpl b/templates/management/access.tpl
index a39482b6569..0ffcc7b7cce 100644
--- a/templates/management/access.tpl
+++ b/templates/management/access.tpl
@@ -18,6 +18,7 @@
+
{include file="management/accessUsers.tpl"}
From 38ed428fe158c773a3eef4c56674a5c1213b0513 Mon Sep 17 00:00:00 2001
From: ipula
Date: Thu, 24 Oct 2024 16:49:42 +0200
Subject: [PATCH 20/26] add userOrcid into validateFields
---
classes/invitation/stepTypes/AcceptInvitationStep.php | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php
index 59e7a8d1de6..15babd571d0 100644
--- a/classes/invitation/stepTypes/AcceptInvitationStep.php
+++ b/classes/invitation/stepTypes/AcceptInvitationStep.php
@@ -63,7 +63,7 @@ private function verifyOrcidStep(): \stdClass
$sections->addSection(
null,
[
- 'validateFields' => []
+ 'validateFields' => ['userOrcid']
]
);
$step = new Step(
@@ -135,9 +135,7 @@ private function userDetailsStep(Context $context): \stdClass
),
[
'validateFields' => [
- 'affiliation',
'givenName',
- 'familyName',
'userCountry',
]
]
From 240e2e2eed13a8520e4050fb5b5aa7aa4bfeb0fb Mon Sep 17 00:00:00 2001
From: ipula
Date: Thu, 24 Oct 2024 18:42:10 +0200
Subject: [PATCH 21/26] add user details step validate fields
---
classes/invitation/stepTypes/AcceptInvitationStep.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php
index 15babd571d0..5a6ec1874e9 100644
--- a/classes/invitation/stepTypes/AcceptInvitationStep.php
+++ b/classes/invitation/stepTypes/AcceptInvitationStep.php
@@ -135,7 +135,9 @@ private function userDetailsStep(Context $context): \stdClass
),
[
'validateFields' => [
+ 'affiliation',
'givenName',
+ 'familyName',
'userCountry',
]
]
From f7758b0b9849c6767d9cbc9ba372b980ad6f4916 Mon Sep 17 00:00:00 2001
From: ipula
Date: Mon, 28 Oct 2024 16:16:48 +0100
Subject: [PATCH 22/26] add user object into steps
---
.../handlers/UserRoleAssignmentInviteRedirectController.php | 5 ++++-
classes/invitation/stepTypes/AcceptInvitationStep.php | 6 +++---
classes/invitation/stepTypes/InvitationStepTypes.php | 3 ++-
classes/invitation/stepTypes/SendInvitationStep.php | 5 +++--
pages/invitation/InvitationHandler.php | 2 +-
5 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
index 07b923a5868..486af2de884 100644
--- a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
+++ b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
@@ -21,6 +21,7 @@
use PKP\invitation\core\InvitationActionRedirectController;
use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite;
use PKP\invitation\stepTypes\AcceptInvitationStep;
+use APP\facades\Repo;
class UserRoleAssignmentInviteRedirectController extends InvitationActionRedirectController
{
@@ -35,8 +36,10 @@ public function acceptHandle(Request $request): void
$templateMgr->assign('invitation', $this->invitation);
$context = $request->getContext();
$steps = new AcceptInvitationStep();
+ $invitationModel = $this->invitation->invitationModel->toArray();
+ $user = $invitationModel['userId'] ?Repo::user()->get($invitationModel['userId']) : null;
$templateMgr->setState([
- 'steps' => $steps->getSteps($this->invitation, $context),
+ 'steps' => $steps->getSteps($this->invitation, $context,$user),
'primaryLocale' => $context->getData('primaryLocale'),
'pageTitle' => __('invitation.wizard.pageTitle'),
'invitationId' => (int)$request->getUserVar('id') ?: null,
diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php
index 5a6ec1874e9..8b6f9bf691f 100644
--- a/classes/invitation/stepTypes/AcceptInvitationStep.php
+++ b/classes/invitation/stepTypes/AcceptInvitationStep.php
@@ -19,6 +19,7 @@
use PKP\invitation\sections\Form;
use PKP\invitation\sections\Sections;
use PKP\invitation\steps\Step;
+use PKP\user\User;
class AcceptInvitationStep extends InvitationStepTypes
{
@@ -27,13 +28,12 @@ class AcceptInvitationStep extends InvitationStepTypes
*
* @throws \Exception
*/
- public function getSteps(?Invitation $invitation, Context $context): array
+ public function getSteps(?Invitation $invitation, Context $context, ?User $user): array
{
$steps = [];
- switch ($invitation->invitationModel->userId) {
+ switch ($user) {
case !null:
- $user = Repo::user()->get($invitation->invitationModel->userId);
if(!$user->getData('orcidAccessToken')) {
$steps[] = $this->verifyOrcidStep();
$steps[] = $this->acceptInvitationReviewStep($context);
diff --git a/classes/invitation/stepTypes/InvitationStepTypes.php b/classes/invitation/stepTypes/InvitationStepTypes.php
index 6bb90f28feb..31125e49408 100644
--- a/classes/invitation/stepTypes/InvitationStepTypes.php
+++ b/classes/invitation/stepTypes/InvitationStepTypes.php
@@ -15,6 +15,7 @@
use PKP\context\Context;
use PKP\invitation\core\Invitation;
use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite;
+use PKP\user\User;
abstract class InvitationStepTypes
{
@@ -22,7 +23,7 @@ abstract class InvitationStepTypes
* Get the invitation steps
* use of the built-in UI for making the invitation
*/
- abstract public function getSteps(?Invitation $invitation, Context $context);
+ abstract public function getSteps(?Invitation $invitation, Context $context, ?User $user): array;
/** fake invitation for email template
*/
diff --git a/classes/invitation/stepTypes/SendInvitationStep.php b/classes/invitation/stepTypes/SendInvitationStep.php
index 99f67ccf91b..898884dd6b2 100644
--- a/classes/invitation/stepTypes/SendInvitationStep.php
+++ b/classes/invitation/stepTypes/SendInvitationStep.php
@@ -23,6 +23,7 @@
use PKP\invitation\sections\Sections;
use PKP\invitation\steps\Step;
use PKP\mail\mailables\UserRoleAssignmentInvitationNotify;
+use PKP\user\User;
use stdClass;
class SendInvitationStep extends InvitationStepTypes
@@ -32,10 +33,10 @@ class SendInvitationStep extends InvitationStepTypes
*
* @throws Exception
*/
- public function getSteps(?Invitation $invitation, Context $context): array
+ public function getSteps(?Invitation $invitation, Context $context,?User $user): array
{
$steps = [];
- if(!$invitation) {
+ if(!$invitation && !$user) {
$steps[] = $this->invitationSearchUser();
}
$steps[] = $this->invitationDetailsForm($context);
diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php
index cdb529b7308..1f474896e4e 100644
--- a/pages/invitation/InvitationHandler.php
+++ b/pages/invitation/InvitationHandler.php
@@ -183,7 +183,7 @@ public function invite($args, $request): void
];
$steps = new SendInvitationStep();
$templateMgr->setState([
- 'steps' => $steps->getSteps($invitation, $context),
+ 'steps' => $steps->getSteps($invitation, $context,$user),
'emailTemplatesApiUrl' => $request
->getDispatcher()
->url(
From 0927b8b50bd6ac5a99a645c19e190347f15e2912 Mon Sep 17 00:00:00 2001
From: ipula
Date: Mon, 28 Oct 2024 16:41:06 +0100
Subject: [PATCH 23/26] add comments to functions
---
.../invitation/stepTypes/AcceptInvitationStep.php | 1 +
pages/invitation/InvitationHandler.php | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php
index 8b6f9bf691f..d5a4813c0b4 100644
--- a/classes/invitation/stepTypes/AcceptInvitationStep.php
+++ b/classes/invitation/stepTypes/AcceptInvitationStep.php
@@ -194,6 +194,7 @@ private function acceptInvitationReviewStep(Context $context): \stdClass
}
/**
+ * Get all form locals
* @param Context $context
* @return array
*/
diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php
index 1f474896e4e..31c5431bf68 100644
--- a/pages/invitation/InvitationHandler.php
+++ b/pages/invitation/InvitationHandler.php
@@ -109,6 +109,13 @@ public static function getActionUrl(InvitationAction $action, Invitation $invita
);
}
+ /**
+ * Create an invitation to accept new role
+ * @param $args
+ * @param $request
+ * @return void
+ * @throws \Exception
+ */
public function invite($args, $request): void
{
$invitationMode = 'create';
@@ -216,6 +223,11 @@ public function invite($args, $request): void
$templateMgr->display('/invitation/userInvitation.tpl');
}
+ /**
+ * Get current user user groups
+ * @param $id
+ * @return array
+ */
private function getUserUserGroups($id): array
{
$output = [];
From 1960392409b0c04f749b86cf165cd7b40129d7cd Mon Sep 17 00:00:00 2001
From: ipula
Date: Wed, 30 Oct 2024 16:20:21 +0100
Subject: [PATCH 24/26] fix requested changes in review
---
.../invitation/AcceptUserDetailsForm.php | 4 +-
.../forms/invitation/UserDetailsForm.php | 7 +--
...RoleAssignmentInviteRedirectController.php | 16 ++++-
classes/invitation/sections/Email.php | 11 ++++
classes/invitation/sections/Form.php | 4 ++
classes/invitation/sections/Sections.php | 7 ++-
.../stepTypes/AcceptInvitationStep.php | 33 +++++-----
.../stepTypes/SendInvitationStep.php | 31 +++++-----
classes/invitation/steps/Step.php | 2 +-
locale/en/invitation.po | 62 ++++---------------
locale/en/user.po | 2 +-
pages/invitation/InvitationHandler.php | 22 ++++---
templates/invitation/acceptInvitation.tpl | 12 ++--
templates/invitation/userInvitation.tpl | 18 +++---
14 files changed, 116 insertions(+), 115 deletions(-)
diff --git a/classes/components/forms/invitation/AcceptUserDetailsForm.php b/classes/components/forms/invitation/AcceptUserDetailsForm.php
index 532ed843537..19e73b0dcae 100644
--- a/classes/components/forms/invitation/AcceptUserDetailsForm.php
+++ b/classes/components/forms/invitation/AcceptUserDetailsForm.php
@@ -19,11 +19,11 @@
use PKP\components\forms\FormComponent;
use PKP\facades\Locale;
-define('ACCEPT_FORM_USER_DETAILS', 'acceptUserDetails');
class AcceptUserDetailsForm extends FormComponent
{
+ public const ACCEPT_FORM_USER_DETAILS = 'acceptUserDetails';
/** @copydoc FormComponent::$id */
- public $id = ACCEPT_FORM_USER_DETAILS;
+ public $id = self::ACCEPT_FORM_USER_DETAILS;
/** @copydoc FormComponent::$method */
public $method = 'POST';
diff --git a/classes/components/forms/invitation/UserDetailsForm.php b/classes/components/forms/invitation/UserDetailsForm.php
index 01306aec5f4..c892e0a7c32 100644
--- a/classes/components/forms/invitation/UserDetailsForm.php
+++ b/classes/components/forms/invitation/UserDetailsForm.php
@@ -18,11 +18,11 @@
use PKP\components\forms\FieldText;
use PKP\components\forms\FormComponent;
-define('FORM_USER_DETAILS', 'userDetails');
class UserDetailsForm extends FormComponent
{
+ public const FORM_USER_DETAILS = 'userDetails';
/** @copydoc FormComponent::$id */
- public $id = FORM_USER_DETAILS;
+ public $id = self::FORM_USER_DETAILS;
/** @copydoc FormComponent::$method */
public $method = 'POST';
@@ -32,9 +32,8 @@ class UserDetailsForm extends FormComponent
*
* @param string $action URL to submit the form to
* @param array $locales Supported locales
- * @param \PKP\context\Context $context Journal or Press to change settings for
*/
- public function __construct($action, $locales, $context)
+ public function __construct(string $action, array $locales)
{
$this->action = $action;
$this->locales = $locales;
diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
index 486af2de884..6fa237e5fb9 100644
--- a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
+++ b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php
@@ -30,6 +30,12 @@ public function getInvitation(): UserRoleAssignmentInvite
return $this->invitation;
}
+ /**
+ * Redirect to accept invitation page
+ * @param Request $request
+ * @return void
+ * @throws \Exception
+ */
public function acceptHandle(Request $request): void
{
$templateMgr = TemplateManager::getManager($request);
@@ -39,7 +45,7 @@ public function acceptHandle(Request $request): void
$invitationModel = $this->invitation->invitationModel->toArray();
$user = $invitationModel['userId'] ?Repo::user()->get($invitationModel['userId']) : null;
$templateMgr->setState([
- 'steps' => $steps->getSteps($this->invitation, $context,$user),
+ 'steps' => $steps->getSteps($this->invitation,$context,$user),
'primaryLocale' => $context->getData('primaryLocale'),
'pageTitle' => __('invitation.wizard.pageTitle'),
'invitationId' => (int)$request->getUserVar('id') ?: null,
@@ -52,10 +58,16 @@ public function acceptHandle(Request $request): void
$templateMgr->display('invitation/acceptInvitation.tpl');
}
+ /**
+ * Redirect to login page after decline invitation
+ * @param Request $request
+ * @return void
+ * @throws \Exception
+ */
public function declineHandle(Request $request): void
{
if ($this->invitation->getStatus() !== InvitationStatus::PENDING) {
- $request->getDispatcher()->handle404();
+ $request->getDispatcher()->handle404('The link is deactivated as the invitation was cancelled');
}
$context = $request->getContext();
diff --git a/classes/invitation/sections/Email.php b/classes/invitation/sections/Email.php
index 8e80d42a2bf..614b1c05a8e 100644
--- a/classes/invitation/sections/Email.php
+++ b/classes/invitation/sections/Email.php
@@ -44,6 +44,9 @@ public function __construct(string $id, string $name, string $description, array
$this->recipients = $recipients;
}
+ /**
+ * @inheritDoc
+ */
public function getState(): stdClass
{
$config = parent::getState();
@@ -59,6 +62,10 @@ public function getState(): stdClass
return $config;
}
+ /**
+ * Get all email recipients for email composer
+ * @return array
+ */
protected function getRecipientOptions(): array
{
$recipientOptions = [];
@@ -75,6 +82,10 @@ protected function getRecipientOptions(): array
return $recipientOptions;
}
+ /**
+ * Get all email templates for email composer
+ * @return array
+ */
protected function getEmailTemplates(): array
{
$request = Application::get()->getRequest();
diff --git a/classes/invitation/sections/Form.php b/classes/invitation/sections/Form.php
index c62ba7fb3db..01c58912b6d 100644
--- a/classes/invitation/sections/Form.php
+++ b/classes/invitation/sections/Form.php
@@ -32,6 +32,10 @@ public function __construct(string $id, string $name, string $description, FormC
$this->form = $form;
}
+ /**
+ * @inheritDoc
+ * @throws Exception
+ */
public function getState(): stdClass
{
$config = parent::getState();
diff --git a/classes/invitation/sections/Sections.php b/classes/invitation/sections/Sections.php
index abce3d0f69b..09628cac220 100644
--- a/classes/invitation/sections/Sections.php
+++ b/classes/invitation/sections/Sections.php
@@ -23,8 +23,13 @@ class Sections
public array $props = [];
/**
+ * @param string $id A unique id for this section
+ * @param string $name The name of this section
+ * @param string $type section type eg: form
+ * @param string $sectionComponent A vuejs component for this section
+ * @param string $description description of this section
*/
- public function __construct(string $id, string $name, string $description = '', string $type, string $sectionComponent)
+ public function __construct(string $id, string $name, string $type, string $sectionComponent,string $description = '')
{
$this->id = $id;
$this->name = $name;
diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php
index d5a4813c0b4..ec1783ab7b3 100644
--- a/classes/invitation/stepTypes/AcceptInvitationStep.php
+++ b/classes/invitation/stepTypes/AcceptInvitationStep.php
@@ -12,7 +12,6 @@
*/
namespace PKP\invitation\stepTypes;
-use APP\facades\Repo;
use PKP\components\forms\invitation\AcceptUserDetailsForm;
use PKP\context\Context;
use PKP\invitation\core\Invitation;
@@ -56,9 +55,9 @@ private function verifyOrcidStep(): \stdClass
$sections = new Sections(
'userVerifyOrcid',
__('acceptInvitation.verifyOrcid.stepName'),
- __('userInvitation.searchUser.stepDescription'),
'popup',
- 'AcceptInvitationVerifyOrcid'
+ 'AcceptInvitationVerifyOrcid',
+ __('userInvitation.searchUser.stepDescription'),
);
$sections->addSection(
null,
@@ -69,10 +68,10 @@ private function verifyOrcidStep(): \stdClass
$step = new Step(
'verifyOrcid',
__('acceptInvitation.verifyOrcid.stepName'),
- __('acceptInvitation.verifyOrcid.stepDescription'),
__('acceptInvitation.verifyOrcid.stepLabel'),
__('userInvitation.verifyOrcid.nextButtonLabel'),
- 'popup'
+ 'popup',
+ __('acceptInvitation.verifyOrcid.stepDescription'),
);
$step->addSectionToStep($sections->getState());
return $step->getState();
@@ -86,9 +85,9 @@ private function userAccountDetailsStep(): \stdClass
$sections = new Sections(
'userCreateForm',
__('acceptInvitation.accountDetails.stepName'),
- __('userInvitation.accountDetails.stepDescription'),
'form',
- 'AcceptInvitationUserAccountDetails'
+ 'AcceptInvitationUserAccountDetails',
+ __('userInvitation.accountDetails.stepDescription'),
);
$sections->addSection(
null,
@@ -103,10 +102,10 @@ private function userAccountDetailsStep(): \stdClass
$step = new Step(
'userCreate',
__('acceptInvitation.accountDetails.stepName'),
- __('acceptInvitation.accountDetails.stepDescription'),
__('acceptInvitation.accountDetails.stepLabel'),
__('acceptInvitation.accountDetails.nextButtonLabel'),
- 'form'
+ 'form',
+ __('acceptInvitation.accountDetails.stepDescription'),
);
$step->addSectionToStep($sections->getState());
return $step->getState();
@@ -122,9 +121,9 @@ private function userDetailsStep(Context $context): \stdClass
$sections = new Sections(
'userCreateForm',
__('acceptInvitation.accountDetails.stepName'),
- __('userInvitation.accountDetails.stepDescription'),
'form',
- 'AcceptInvitationUserDetailsForms'
+ 'AcceptInvitationUserDetailsForms',
+ __('userInvitation.accountDetails.stepDescription'),
);
$sections->addSection(
new Form(
@@ -145,10 +144,10 @@ private function userDetailsStep(Context $context): \stdClass
$step = new Step(
'userDetails',
__('acceptInvitation.userDetails.stepName'),
- __('acceptInvitation.userDetails.stepDescription'),
__('acceptInvitation.userDetails.stepLabel'),
__('acceptInvitation.userDetails.nextButtonLabel'),
- 'form'
+ 'form',
+ __('acceptInvitation.userDetails.stepDescription'),
);
$step->addSectionToStep($sections->getState());
return $step->getState();
@@ -164,9 +163,9 @@ private function acceptInvitationReviewStep(Context $context): \stdClass
$sections = new Sections(
'userCreateRoles',
'',
- '',
'table',
- 'AcceptInvitationReview'
+ 'AcceptInvitationReview',
+ ''
);
$sections->addSection(
new Form(
@@ -184,10 +183,10 @@ private function acceptInvitationReviewStep(Context $context): \stdClass
$step = new Step(
'userCreateReview',
__('acceptInvitation.detailsReview.stepName'),
- __('acceptInvitation.detailsReview.stepDescription'),
__('acceptInvitation.detailsReview.stepLabel'),
__('acceptInvitation.detailsReview.nextButtonLabel'),
- 'review'
+ 'review',
+ __('acceptInvitation.detailsReview.stepDescription'),
);
$step->addSectionToStep($sections->getState());
return $step->getState();
diff --git a/classes/invitation/stepTypes/SendInvitationStep.php b/classes/invitation/stepTypes/SendInvitationStep.php
index 898884dd6b2..14e896c9a0e 100644
--- a/classes/invitation/stepTypes/SendInvitationStep.php
+++ b/classes/invitation/stepTypes/SendInvitationStep.php
@@ -52,10 +52,9 @@ private function invitationSearchUser(): stdClass
$sections = new Sections(
'searchUserForm',
__('userInvitation.searchUser.stepName'),
- __('userInvitation.searchUser.stepDescription'),
'form',
'UserInvitationSearchFormStep',
- true
+ __('userInvitation.searchUser.stepDescription'),
);
$sections->addSection(
null,
@@ -66,10 +65,10 @@ private function invitationSearchUser(): stdClass
$step = new Step(
'searchUser',
__('userInvitation.searchUser.stepName'),
- __('userInvitation.searchUser.stepDescription'),
__('userInvitation.searchUser.stepLabel'),
__('userInvitation.searchUser.nextButtonLabel'),
'emptySection',
+ __('userInvitation.searchUser.stepDescription'),
true
);
$step->addSectionToStep($sections->getState());
@@ -94,29 +93,29 @@ private function invitationDetailsForm(Context $context): stdClass
$sections = new Sections(
'userDetails',
__('userInvitation.enterDetails.stepName'),
- __('userInvitation.enterDetails.stepDescription'),
'form',
- 'UserInvitationDetailsFormStep'
+ 'UserInvitationDetailsFormStep',
+ __('userInvitation.enterDetails.stepDescription'),
);
$sections->addSection(
new Form(
'userDetails',
__('userInvitation.enterDetails.stepName'),
__('userInvitation.enterDetails.stepDescription'),
- new UserDetailsForm('users', $locales, $context),
+ new UserDetailsForm('users', $locales),
),
[
'validateFields' => [],
- 'userGroups' => $this->getAllUserGroup($context)
+ 'userGroups' => $this->getAllUserGroups($context)
]
);
$step = new Step(
'userDetails',
__('userInvitation.enterDetails.stepName'),
- __('userInvitation.enterDetails.stepDescription'),
__('userInvitation.enterDetails.stepLabel'),
__('userInvitation.enterDetails.nextButtonLabel'),
- 'form'
+ 'form',
+ __('userInvitation.enterDetails.stepDescription'),
);
$step->addSectionToStep($sections->getState());
return $step->getState();
@@ -132,9 +131,9 @@ private function invitationInvitedEmail(Context $context): stdClass
$sections = new Sections(
'userInvitedEmail',
__('userInvitation.sendMail.stepLabel'),
- __('userInvitation.sendMail.stepName'),
'email',
- 'UserInvitationEmailComposerStep'
+ 'UserInvitationEmailComposerStep',
+ __('userInvitation.sendMail.stepName'),
);
$fakeInvitation = $this->getFakeInvitation();
$mailable = new UserRoleAssignmentInvitationNotify($context, $fakeInvitation);
@@ -157,19 +156,21 @@ private function invitationInvitedEmail(Context $context): stdClass
$step = new Step(
'userInvited',
__('userInvitation.sendMail.stepName'),
- __('userInvitation.sendMail.stepDescription'),
__('userInvitation.sendMail.stepLabel'),
__('userInvitation.sendMail.nextButtonLabel'),
- 'email'
+ 'email',
+ __('userInvitation.sendMail.stepDescription'),
);
$step->addSectionToStep($sections->getState());
return $step->getState();
}
/**
- * get all user groups
+ * Get all user groups
+ * @param Context $context
+ * @return array
*/
- private function getAllUserGroup(Context $context): array
+ private function getAllUserGroups(Context $context): array
{
$allUserGroups = [];
$userGroups = Repo::userGroup()->getCollector()
diff --git a/classes/invitation/steps/Step.php b/classes/invitation/steps/Step.php
index adf35516516..d21ee51980d 100644
--- a/classes/invitation/steps/Step.php
+++ b/classes/invitation/steps/Step.php
@@ -35,7 +35,7 @@ class Step
* @param string $type A type of this step.
* @param bool $skipInvitationUpdate Skip invitation update.
*/
- public function __construct(string $id, string $name, string $description = '', string $stepLabel, string $nextButtonLabel, string $type, bool $skipInvitationUpdate = false)
+ public function __construct(string $id, string $name, string $stepLabel, string $nextButtonLabel, string $type, string $description = '', bool $skipInvitationUpdate = false)
{
$this->id = $id;
$this->name = $name;
diff --git a/locale/en/invitation.po b/locale/en/invitation.po
index e8d31c12a45..9d1e753239a 100644
--- a/locale/en/invitation.po
+++ b/locale/en/invitation.po
@@ -115,9 +115,6 @@ msgstr "Invite to a role"
msgid "invitation.wizard.pageTitle"
msgstr "Invite user to take a role"
-msgid "invitation.wizard.pageTitleDescription"
-msgstr "You are inviting a user to take a role in OJS along with appearing in the journal masthead"
-
msgid "userInvitation.enterDetailsLabel"
msgstr "Enter details"
@@ -134,7 +131,7 @@ msgid "userInvitation.searchUser.nextButtonLabel"
msgstr "Search User"
msgid "userInvitation.searchUser.stepDescription"
-msgstr "Search for the user using their email address, username or ORCID ID. Enter at least one details to get started. If user does not exist, ypu can invite them to take up roles and be a part of your journal. If the user already exist in the system, you can view user information and invite to take a additional roles."
+msgstr "Search for the user using their email address, username or ORCID ID. Enter at least one details to get started. If the user does not exist, you can invite them to take up roles and be a part of your journal. If the user already exist in the system, you can view user information and invite to take a additional roles."
msgid "userInvitation.emailField.description"
msgstr "e.g. aeinstein@example.com"
@@ -151,9 +148,6 @@ msgstr "Enter details"
msgid "userInvitation.enterDetails.stepLabel"
msgstr "{$step} - Enter details and invite for roles"
-msgid "userInvitation.enterDetails.stepDescription"
-msgstr "You can invite them to take up a role in OJS"
-
msgid "userInvitation.enterDetails.nextButtonLabel"
msgstr "Save And Continue"
@@ -191,7 +185,7 @@ msgid "userInvitation.sendMail.nextButtonLabel"
msgstr "Invite user to the role"
msgid "userInvitation.sendMail.stepDescription"
-msgstr "Send the user an email to let them know about the invitation, next steps, journal GDPR polices and ORCiD verification"
+msgstr "Send the user an email to let them know about the invitation, next steps, journal GDPR polices and ORCID verification"
msgid "userInvitation.sendMail.stepLabel"
msgstr "{$step} - Modify email shared with the user"
@@ -199,9 +193,6 @@ msgstr "{$step} - Modify email shared with the user"
msgid "userInvitation.modal.title"
msgstr "Invitation Sent"
-msgid "userInvitation.modal.message"
-msgstr "{$email} has been invited to new role in OJS.You can be updated about users on the User and Roles page, your ojs notification and/ or your email"
-
msgid "userInvitation.modal.button"
msgstr "View All Users"
@@ -215,10 +206,10 @@ msgid "invitation.orcid.description"
msgstr "On accepting the invite, the user will be redirected to ORCID to verify their account, if they wish to."
msgid "invitation.givenName.description"
-msgstr "If you know the given name of the user, you can enter the information. However, this information can be changed by the user"
+msgstr "If you know the given name of the user, you can enter the information. However, this information can be changed by the user."
msgid "invitation.familyName.description"
-msgstr "If you know the family name of the user, you can enter the information. However, this information can be changed by the user"
+msgstr "If you know the family name of the user, you can enter the information. However, this information can be changed by the user."
msgid "acceptInvitation.verifyOrcid.stepName"
msgstr "Verify ORCID iD"
@@ -226,21 +217,9 @@ msgstr "Verify ORCID iD"
msgid "acceptInvitation.verifyOrcid.stepLabel"
msgstr "{$step} - Verify ORCID iD"
-msgid "acceptInvitation.verifyOrcid.stepDescription"
-msgstr "You can choose to verify your ORCID iD ok skip it. If you chose to skip it now, You can verify your ORCID iD from your profile section in OJS later"
-
msgid "acceptInvitation.verifyOrcid.nextButtonLabel"
msgstr "Save and continue"
-msgid "acceptInvitation.accountDetails.stepName"
-msgstr "Create OJS account"
-
-msgid "acceptInvitation.accountDetails.stepLabel"
-msgstr "{$step} - Create OJS account"
-
-msgid "acceptInvitation.accountDetails.stepDescription"
-msgstr "To get started with OJS and accept the new role, you will need to create an account with us. For this purpose please enter a username and password."
-
msgid "acceptInvitation.accountDetails.nextButtonLabel"
msgstr "Save and continue"
@@ -251,7 +230,7 @@ msgid "acceptInvitation.userDetails.stepLabel"
msgstr "{$step} - Enter details"
msgid "acceptInvitation.userDetails.stepDescription"
-msgstr "Enter your details like email ID, affiliation ect. As per the GDPR compliance, this information can only modified by you. You can also choose if you want this information to be visible on your profile to the editor."
+msgstr "Enter your details like email ID, affiliation etc. As per the GDPR compliance, this information can only modified by you. You can also choose if you want this information to be visible on your profile to the editor."
msgid "acceptInvitation.userDetails.nextButtonLabel"
msgstr "Save and continue"
@@ -268,12 +247,6 @@ msgstr "Review & create account"
msgid "acceptInvitation.detailsReview.stepLabel"
msgstr "{$step} - Review & create account"
-msgid "acceptInvitation.detailsReview.stepDescription"
-msgstr "Review details to start your new roles in OJS"
-
-msgid "acceptInvitation.detailsReview.nextButtonLabel"
-msgstr "Accept And Continue to OJS"
-
msgid "acceptInvitation.skipVerifyOrcid"
msgstr "Skip ORCID verification"
@@ -281,10 +254,10 @@ msgid "acceptInvitation.verifyOrcid"
msgstr "Verify ORCID iD"
msgid "acceptInvitation.usernameField.description"
-msgstr "It should be 10 characters long and could be a combination of uppercase letters, lowercase letters or numbers"
+msgstr "It could be a combination of uppercase letters, lowercase letters or numbers"
msgid "acceptInvitation.passwordField.description"
-msgstr "It should be 12 characters long and should be a combination of uppercase letters, lowercase letters, numbers and symbols"
+msgstr "It should be at least 6 characters long and could be a combination of uppercase letters, lowercase letters, numbers and symbols"
msgid "acceptInvitation.privacyStatement.label"
msgstr "Yes, I agree to have my data collected and stored according to the"
@@ -293,10 +266,10 @@ msgid "acceptInvitation.privacyStatement.btn"
msgstr "Privacy Statement"
msgid "acceptInvitation.userDetailsForm.givenName.description"
-msgstr "Also known as a forename or the first name, it is tha part of a personal name that identifies a preson"
+msgstr "Also known as a forename or the first name, it is tha part of a personal name that identifies a person."
msgid "acceptInvitation.userDetailsForm.familyName.description"
-msgstr "A surname, family name, or last name is the mostly hereditary portion of one's personal name that indicates one's family"
+msgstr "A surname, family name, or last name is the mostly hereditary portion of one's personal name that indicates one's family."
msgid "acceptInvitation.userDetailsForm.affiliation.description"
msgstr "This is the institute you are affiliated with"
@@ -313,15 +286,6 @@ msgstr "Account Details"
msgid "acceptInvitation.review.userDetails"
msgstr "User Details"
-msgid "invitation.orcid.acceptInvitation.message"
-msgstr "Not verified. You can verify your ORCID iD from your profile section in OJS"
-
-msgid "acceptInvitation.modal.title"
-msgstr "You've been assigned a new role in OJS"
-
-msgid "acceptInvitation.modal.message"
-msgstr "Congratulations on your new role in OJS! You might now have access to new options. If you need assistance navigating the system, please click on the “Help” buttons throughout the interface for guidance"
-
msgid "acceptInvitation.modal.button"
msgstr "View All Submissions"
@@ -329,7 +293,7 @@ msgid "invitation.tableHeader.name"
msgstr "Name"
msgid "invitation.searchForm.emptyError"
-msgstr "At least provide one search criteria."
+msgstr "Provide at least one search criteria."
msgid "invitation.wizard.viewPageTitleDescription"
msgstr "You are viewing {$name}'s user details"
@@ -362,7 +326,7 @@ msgid "invitation.cancelInvite.title"
msgstr "Cancel Invitation"
msgid "invitation.cancelInvite.message"
-msgstr "Cancel the invitation sent to {$givenName} {$familyName} will deactivate acceptance link sent via email. Here are the invitation details: "
+msgstr "Canceling the invitation sent to {$givenName} {$familyName} will deactivate acceptance link sent via email. Here are the invitation details: "
msgid "invitation.masthead.show"
msgstr "Appear on the masthead"
@@ -377,7 +341,7 @@ msgid "invitation.management.options"
msgstr "Invitation management options"
msgid "userInvitation.cancel.message"
-msgstr "Are you sure want to cancel this invitation ?"
+msgstr "Are you sure want to cancel this invitation?"
msgid "userInvitation.cancel.keepWorking"
msgstr "Keep Working"
@@ -407,4 +371,4 @@ msgid "acceptInvitation.privacyStatement.validation"
msgstr "Please confirm that you have read and agree privacy statement"
msgid "acceptInvitation.cancel.message"
-msgstr "Are you sure want to cancel accepting invitation ?"
+msgstr "Are you sure want to cancel accepting invitation?"
diff --git a/locale/en/user.po b/locale/en/user.po
index 0bd2b34d368..1d9a96a9848 100644
--- a/locale/en/user.po
+++ b/locale/en/user.po
@@ -790,4 +790,4 @@ msgid "orcid.field.unverified.shouldRequest"
msgstr "This ORCID has not been verified. Please remove this unverified ORCID and request verification from the user/author directly."
msgid "user.removeRole.message"
-msgstr "Are you sure want remove this role permanently ?"
+msgstr "Are you sure want remove this role permanently?"
diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php
index 31c5431bf68..28345859a73 100644
--- a/pages/invitation/InvitationHandler.php
+++ b/pages/invitation/InvitationHandler.php
@@ -71,7 +71,13 @@ private function getInvitationByKey(Request $request): Invitation
return $invitation;
}
- private function getInvitationById(Request $request, $id): Invitation
+ /**
+ * Get invitation by invitation id
+ * @param Request $request
+ * @param int $id
+ * @return Invitation
+ */
+ private function getInvitationById(Request $request, int $id): Invitation
{
$invitation = Repo::invitation()
->getById($id);
@@ -111,12 +117,12 @@ public static function getActionUrl(InvitationAction $action, Invitation $invita
/**
* Create an invitation to accept new role
- * @param $args
- * @param $request
+ * @param array $args
+ * @param Request $request
* @return void
* @throws \Exception
*/
- public function invite($args, $request): void
+ public function invite(array $args, Request $request): void
{
$invitationMode = 'create';
$invitationPayload = [
@@ -154,7 +160,7 @@ public function invite($args, $request): void
}
$invitationPayload['userId'] = $invitationModel['userId'];
$invitationPayload['inviteeEmail'] = $invitationModel['email'] ?: $user->getEmail();
- $invitationPayload['orcid'] = $payload['orcid']; //$reviewer->getData('orcidAccessToken')
+ $invitationPayload['orcid'] = $payload['orcid'];
$invitationPayload['givenName'] = $user ? $user->getGivenName(null) : $payload['givenName'];
$invitationPayload['familyName'] = $user ? $user->getFamilyName(null) : $payload['familyName'];
$invitationPayload['affiliation'] = $user ? $user->getAffiliation(null) : $payload['affiliation'];
@@ -190,7 +196,7 @@ public function invite($args, $request): void
];
$steps = new SendInvitationStep();
$templateMgr->setState([
- 'steps' => $steps->getSteps($invitation, $context,$user),
+ 'steps' => $steps->getSteps($invitation,$context,$user),
'emailTemplatesApiUrl' => $request
->getDispatcher()
->url(
@@ -225,10 +231,10 @@ public function invite($args, $request): void
/**
* Get current user user groups
- * @param $id
+ * @param int $id
* @return array
*/
- private function getUserUserGroups($id): array
+ private function getUserUserGroups(int $id): array
{
$output = [];
$userGroups = Repo::userGroup()->userUserGroups($id);
diff --git a/templates/invitation/acceptInvitation.tpl b/templates/invitation/acceptInvitation.tpl
index 19e2341e217..b2999ad38fc 100644
--- a/templates/invitation/acceptInvitation.tpl
+++ b/templates/invitation/acceptInvitation.tpl
@@ -13,11 +13,11 @@
{extends file="layouts/backend.tpl"}
{block name="page"}
{/block}
diff --git a/templates/invitation/userInvitation.tpl b/templates/invitation/userInvitation.tpl
index e28201ece18..2216ddff415 100644
--- a/templates/invitation/userInvitation.tpl
+++ b/templates/invitation/userInvitation.tpl
@@ -1,4 +1,4 @@
-?php
+
{/block}
From d988150cc88386b69db0bcf06b09d4a11724e57d Mon Sep 17 00:00:00 2001
From: ipula
Date: Thu, 31 Oct 2024 11:10:07 +0100
Subject: [PATCH 25/26] fix spaces and local issues
---
classes/invitation/sections/Sections.php | 2 +-
.../invitation/stepTypes/SendInvitationStep.php | 2 +-
locale/en/invitation.po | 17 +----------------
templates/management/access.tpl | 2 +-
4 files changed, 4 insertions(+), 19 deletions(-)
diff --git a/classes/invitation/sections/Sections.php b/classes/invitation/sections/Sections.php
index 09628cac220..a433adad326 100644
--- a/classes/invitation/sections/Sections.php
+++ b/classes/invitation/sections/Sections.php
@@ -29,7 +29,7 @@ class Sections
* @param string $sectionComponent A vuejs component for this section
* @param string $description description of this section
*/
- public function __construct(string $id, string $name, string $type, string $sectionComponent,string $description = '')
+ public function __construct(string $id, string $name, string $type, string $sectionComponent, string $description = '')
{
$this->id = $id;
$this->name = $name;
diff --git a/classes/invitation/stepTypes/SendInvitationStep.php b/classes/invitation/stepTypes/SendInvitationStep.php
index 14e896c9a0e..2344910e782 100644
--- a/classes/invitation/stepTypes/SendInvitationStep.php
+++ b/classes/invitation/stepTypes/SendInvitationStep.php
@@ -33,7 +33,7 @@ class SendInvitationStep extends InvitationStepTypes
*
* @throws Exception
*/
- public function getSteps(?Invitation $invitation, Context $context,?User $user): array
+ public function getSteps(?Invitation $invitation, Context $context, ?User $user): array
{
$steps = [];
if(!$invitation && !$user) {
diff --git a/locale/en/invitation.po b/locale/en/invitation.po
index 9d1e753239a..f822f8d7dc2 100644
--- a/locale/en/invitation.po
+++ b/locale/en/invitation.po
@@ -160,9 +160,6 @@ msgstr "Start Date"
msgid "invitation.role.dateEnd"
msgstr "End Date"
-msgid "invitation.role.masthead"
-msgstr "Journal Masthead"
-
msgid "invitation.role.addRole.button"
msgstr "Add Another Role"
@@ -175,18 +172,12 @@ msgstr "Start Date"
msgid "userInvitation.roleTable.endDate"
msgstr "End Date"
-msgid "userInvitation.roleTable.journalMasthead"
-msgstr "Journal Masthead"
-
msgid "userInvitation.sendMail.stepName"
msgstr "Review & invite for roles"
msgid "userInvitation.sendMail.nextButtonLabel"
msgstr "Invite user to the role"
-msgid "userInvitation.sendMail.stepDescription"
-msgstr "Send the user an email to let them know about the invitation, next steps, journal GDPR polices and ORCID verification"
-
msgid "userInvitation.sendMail.stepLabel"
msgstr "{$step} - Modify email shared with the user"
@@ -260,7 +251,7 @@ msgid "acceptInvitation.passwordField.description"
msgstr "It should be at least 6 characters long and could be a combination of uppercase letters, lowercase letters, numbers and symbols"
msgid "acceptInvitation.privacyStatement.label"
-msgstr "Yes, I agree to have my data collected and stored according to the"
+msgstr "Yes, I agree to have my data collected and stored according to the {$url}"
msgid "acceptInvitation.privacyStatement.btn"
msgstr "Privacy Statement"
@@ -349,12 +340,6 @@ msgstr "Keep Working"
msgid "userInvitation.status.invited"
msgstr "Invited {$date}"
-msgid "userInvitation.search.userNotFound"
-msgstr "The user does not have a role in this journal"
-
-msgid "userInvitation.search.userFound"
-msgstr "The user already exists in the journal"
-
msgid "userInvitation.edit.title"
msgstr "Edit Invitation"
diff --git a/templates/management/access.tpl b/templates/management/access.tpl
index 0ffcc7b7cce..9d10a03e30a 100644
--- a/templates/management/access.tpl
+++ b/templates/management/access.tpl
@@ -18,7 +18,7 @@
-
+
{include file="management/accessUsers.tpl"}
From 730cc7f4aaf5a38ae55e79934d1586eb5e136ff6 Mon Sep 17 00:00:00 2001
From: withanage
Date: Fri, 25 Oct 2024 17:00:53 +0200
Subject: [PATCH 26/26] User search API, return all current and future us ers,
when search status = all
---
classes/user/Collector.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/classes/user/Collector.php b/classes/user/Collector.php
index 804deb05179..f00b529e82d 100644
--- a/classes/user/Collector.php
+++ b/classes/user/Collector.php
@@ -47,7 +47,7 @@ class Collector implements CollectorInterface
public const STATUS_ACTIVE = 'active';
public const STATUS_DISABLED = 'disabled';
- public const STATUS_ALL = null;
+ public const STATUS_ALL = 'all';
public DAO $dao;
@@ -488,6 +488,10 @@ protected function buildUserGroupFilter(Builder $query): self
}
$currentDateTime = Core::getCurrentDate();
+ if ($this->status === self::STATUS_ALL) {
+ $this->userUserGroupStatus = UserUserGroupStatus::STATUS_ALL;
+ }
+
$subQuery = DB::table('user_user_groups as uug')
->join('user_groups AS ug', 'uug.user_group_id', '=', 'ug.user_group_id')
->whereColumn('uug.user_id', '=', 'u.user_id')