Skip to content
Code-Schnipsel Gruppen Projekte

Revisionen vergleichen

Änderungen werden so angezeigt, als ob die Quellrevision mit der Zielrevision zusammengeführt würde. Erfahre mehr über den Vergleich von Revisionen.

Quelle

Zielprojekt auswählen
No results found

Ziel

Zielprojekt auswählen
  • quiqqer/frontend-users
1 Ergebnis
Änderungen anzeigen
Commits auf Quelle (16)
werden angezeigt mit 746 Ergänzungen und 73 Löschungen
# Ignore developer files when exporting
.gitattributes export-ignore
.gitignore export-ignore
.gitlab-ci.yml export-ignore
.phive export-ignore
captainhook.json export-ignore
phpcs.xml.dist export-ignore
phpstan-baseline.neon export-ignore
phpstan.dist.neon export-ignore
phpunit.dist.xml export-ignore
tests export-ignore
# Explicitly set file type and line endings for PHP files, improves git diff output
*.php text eol=lf diff=php
\ No newline at end of file
......@@ -2,3 +2,11 @@ tools/
phpstan.neon
.phpunit.result.cache
phpunit.xml
tools/
phpstan.neon
.phpunit.result.cache
phpunit.xml
include:
- project: 'quiqqer/stabilization/semantic-release'
file: '/ci-templates/.gitlab-ci.yml'
- component: dev.quiqqer.com/quiqqer/stabilization/ci-cd-components/quiqqer-package-bundle/quiqqer-package-bundle@main
# Remove the entire phpunit-php8.1 block, to allow PHPUnit to run on PHP 8.1 in your pipeline
phpunit-php8.1:
rules:
- when: never
# Remove the entire phpunit-php8.2 block, to allow PHPUnit to run on PHP 8.2 in your pipeline
phpunit-php8.2:
rules:
- when: never
# Remove the entire phpunit-php8.3 block, to allow PHPUnit to run on PHP 8.3 in your pipeline
phpunit-php8.3:
rules:
- when: never
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpstan" version="^1.10.67" installed="1.10.67" location="./tools/phpstan" copy="false"/>
<phar name="phpstan" version="1.11.8" installed="1.11.8" location="./tools/phpstan" copy="false"/>
<phar name="phpunit" version="^10.5.20" installed="10.5.20" location="./tools/phpunit" copy="false"/>
<phar name="phpcs" version="^3.10.1" installed="3.10.1" location="./tools/phpcs" copy="false"/>
<phar name="phpcbf" version="^3.10.1" installed="3.10.1" location="./tools/phpcbf" copy="false"/>
<phar name="captainhook" version="^5.23.3" installed="5.23.3" location="./tools/captainhook" copy="false"/>
</phive>
# Contributing
This package follows the [QUIQQER contribution guidelines](https://dev.quiqqer.com/quiqqer/stabilization/documentation/-/wikis/home).
\ No newline at end of file
......@@ -33,6 +33,7 @@
class="field-container-field quiqqer-frontendusers-settings-registrars-setting">
<option value="mail">{{activationModeOptionMail}}</option>
<option value="auto">{{activationModeOptionAuto}}</option>
<option value="autoWithEmailConfirm">{{activationModeOptionAutoWithEmailConfirm}}</option>
<option value="manual">{{activationModeOptionManual}}</option>
</select>
</label>
......
......@@ -19,7 +19,7 @@ define('package/quiqqer/frontend-users/bin/controls/settings/Registrars', [
'css!package/quiqqer/frontend-users/bin/controls/settings/Registrars.css'
], function (QUI, QUIControl, QUILoader, QUIFormUtils, QUILocale, QUIAjax,
Mustache, entryTemplate) {
Mustache, entryTemplate) {
"use strict";
var lg = 'quiqqer/frontend-users';
......@@ -82,14 +82,15 @@ define('package/quiqqer/frontend-users/bin/controls/settings/Registrars', [
'class' : 'quiqqer-frontendusers-settings-registrars-entry',
'data-registrar': Registrar.type,
html : Mustache.render(entryTemplate, {
title : Registrar.title,
description : Registrar.description,
labelActivationMode : QUILocale.get(lg, lgPrefix + 'labelActivationMode'),
activationModeOptionMail : QUILocale.get(lg, lgPrefix + 'activationModeOptionMail'),
activationModeOptionAuto : QUILocale.get(lg, lgPrefix + 'activationModeOptionAuto'),
activationModeOptionManual: QUILocale.get(lg, lgPrefix + 'activationModeOptionManual'),
labelActive : QUILocale.get(lg, lgPrefix + 'labelActive'),
labelDisplayPosition : QUILocale.get(lg, lgPrefix + 'labelDisplayPosition')
title : Registrar.title,
description : Registrar.description,
labelActivationMode : QUILocale.get(lg, lgPrefix + 'labelActivationMode'),
activationModeOptionMail : QUILocale.get(lg, lgPrefix + 'activationModeOptionMail'),
activationModeOptionAuto : QUILocale.get(lg, lgPrefix + 'activationModeOptionAuto'),
activationModeOptionAutoWithEmailConfirm: QUILocale.get(lg, lgPrefix + 'activationModeOptionAutoWithEmailConfirm'),
activationModeOptionManual : QUILocale.get(lg, lgPrefix + 'activationModeOptionManual'),
labelActive : QUILocale.get(lg, lgPrefix + 'labelActive'),
labelDisplayPosition : QUILocale.get(lg, lgPrefix + 'labelDisplayPosition')
})
}).inject(self.$Content);
......
......@@ -1331,7 +1331,10 @@ define('package/quiqqer/frontend-users/bin/frontend/controls/RegistrationSignUp'
duration: 250,
callback: function () {
Captcha.setStyle('display', 'none');
Password.setStyle('display', 'none');
if (Password) {
Password.setStyle('display', 'none');
}
Mail.setStyle('opacity', 0);
Mail.setStyle('display', 'inline');
......
{
"pre-commit": {
"enabled": true,
"actions": [
{
"action": "\\CaptainHook\\App\\Hook\\PHP\\Action\\Linting"
},
{
"action": "composer test"
}
]
}
}
\ No newline at end of file
{
"name": "quiqqer/frontend-users",
"type": "quiqqer-module",
"description": "The Frontend Users module extends QUIQQER with a profile extension and a registration for users.",
"license": "GPL-3.0+",
"authors": [
{
"name": "Henning Leutz",
"email": "support@pcsg.de",
"homepage": "https://www.pcsg.de",
"role": "Developer"
"name": "quiqqer/frontend-users",
"type": "quiqqer-module",
"description": "The Frontend Users module extends QUIQQER with a profile extension and a registration for users.",
"license": "GPL-3.0+",
"authors": [
{
"name": "Henning Leutz",
"email": "support@pcsg.de",
"homepage": "https://www.pcsg.de",
"role": "Developer"
},
{
"name": "Patrick Müller",
"email": "support@pcsg.de",
"homepage": "https://www.pcsg.de",
"role": "Developer"
},
{
"name": "Jan Wennrich",
"email": "support@pcsg.de",
"homepage": "https://www.pcsg.de",
"role": "Developer"
}
],
"support": {
"email": "support@pcsg.de"
},
{
"name": "Patrick M\u00fcller",
"email": "support@pcsg.de",
"homepage": "https://www.pcsg.de",
"role": "Developer"
"require": {
"quiqqer/core": "^2",
"quiqqer/countries": "^2",
"quiqqer/verification": "^2",
"quiqqer/tooltips": "^2",
"quiqqer/data-layer": "^2"
},
{
"name": "Jan Wennrich",
"email": "support@pcsg.de",
"homepage": "https://www.pcsg.de",
"role": "Developer"
}
],
"support": {
"email": "support@pcsg.de"
},
"require": {
"quiqqer/core": "^2",
"quiqqer/countries": "^2",
"quiqqer/verification": "^2",
"quiqqer/tooltips": "^2",
"quiqqer/data-layer": "^2"
},
"suggest": {
"quiqqer/rest": "User registration via REST API"
},
"autoload": {
"psr-4": {
"QUI\\FrontendUsers\\": "src/QUI/FrontendUsers"
"suggest": {
"quiqqer/rest": "User registration via REST API"
},
"autoload": {
"psr-4": {
"QUI\\FrontendUsers\\": "src/QUI/FrontendUsers"
}
},
"scripts": {
"test": [
"@dev:lint",
"@dev:phpunit"
],
"dev:phpunit": "./tools/phpunit",
"dev:lint": [
"@dev:lint:phpstan",
"@dev:lint:style"
],
"dev:lint:phpstan": "./tools/phpstan",
"dev:lint:style": "./tools/phpcs",
"dev:lint:style:fix": "./tools/phpcbf",
"dev:init": [
"@dev:init:check-requirements",
"@dev:init:tools",
"@dev:init:git-hooks"
],
"dev:init:check-requirements": [
"which composer > /dev/null || (echo 'Error: composer has to be globally installed'; exit 1)",
"which phive > /dev/null || (echo 'Error: PHIVE has to be globally installed'; exit 1)"
],
"dev:init:tools": "phive install --temporary",
"dev:init:git-hooks": "./tools/captainhook install --only-enabled --force"
},
"scripts-aliases": {
"test": [
"dev:test"
]
},
"scripts-descriptions": {
"test": "Runs linting, static analysis, and unit tests.",
"dev:phpunit": "Run PHPUnit test suites",
"dev:lint": "Run PHPStan and code style check",
"dev:lint:phpstan": "Run PHPStan",
"dev:lint:style": "Run code style check (PHP_CodeSniffer)",
"dev:lint:style:fix": "Try to fix code style errors automatically",
"dev:init": "Initialize the developer tooling (tools and git hooks)",
"dev:init:check-requirements": "Check if the necessary requirements are met",
"dev:init:tools": "Install all developer tools (requires PHIVE)",
"dev:init:git-hooks": "Install all git hooks (may require tools to be installed)"
}
}
}
}
\ No newline at end of file
......@@ -1642,6 +1642,32 @@ The e-mail address for your user account on [host] has been changed to the addre
</p>]]></en>
</locale>
<!-- E-Mail-Address confirm mail -->
<locale name="mail.confirm_email_address.subject">
<de><![CDATA[Bestätigung Ihrer E-Mail-Adresse]]></de>
<en><![CDATA[Confirm your email address]]></en>
</locale>
<locale name="mail.confirm_email_address.body" html="true">
<de><![CDATA[<h1>Hallo [username]!</h1>
<p>
Bitte bestätigen Sie Ihre E-Mail-Adresse für Ihr Benutzerkonto auf [host]. Für die Bestätigung öffnen Sie bitte folgenden Link:
<br><br>
<a href="[confirmLink]">[confirmLink]</a>
</p>
<p>
<b>Hinweis:</b> Sollten Sie diese E-Mail nicht veranlasst haben, können Sie sie einfach ignorieren.
</p>]]></de>
<en><![CDATA[<h1>Hello [username]!</h1>
<p>
Please confirm your e-mail address for your user account on [host]. To confirm your e-mail address, please click on the following link:
<br>
<a href="[confirmLink]">[confirmLink]</a>
</p>
<p>
<b>Note:</b> If you have not initiated this email, please ignore this it.
</p>]]></en>
</locale>
<!-- User delete confirm mail -->
<locale name="mail.delete_user_confirm.subject">
<de><![CDATA[Löschung Ihres Benutzerkontos]]></de>
......@@ -1975,6 +2001,58 @@ The deletion of your user account on [host] was requested on [date]. Please conf
]]></en>
</locale>
<locale name="mail.text.confirmEmail.title">
<de><![CDATA[Frontend Users: Bestätigung der E-Mail-Adresse]]></de>
<en><![CDATA[Frontend Users: Confirmation of e-mail address]]></en>
</locale>
<locale name="mail.text.confirmEmail.description">
<de><![CDATA[
E-Mail zur Bestägigung einer E-Mail-Adresse.
]]></de>
<en><![CDATA[
Email for confirmation of an email address.
]]></en>
</locale>
<locale name="order.confirmEmail.subject.description">
<de><![CDATA[
<p>Betreff der Bestätigungs--E-Mail. Verfügbare Variablen:</p>
<ul>
<li><b>[host]:</b> Host des Projektes (System)</li>
</ul>
]]></de>
<en><![CDATA[
<p>Subject of the confirmation e-mail. Available variables:</p>
<ul>
<li><b>[host]:</b> Host of the project (system)</li>
</ul>
]]></en>
</locale>
<locale name="order.confirmEmail.body.description">
<de><![CDATA[
<p>Inhalt der Bestätigungs-E-Mail. Verfügbare Variablen:</p>
<ul>
<li><b>[host]:</b> Host des Projektes (System)</li>
<li><b>[userId]:</b> Benutzer ID</li>
<li><b>[email]:</b> E-Mail des Benutzers</li>
<li><b>[confirmLink]:</b> Bestätigungs-Link (muss enthalten sein!)</li>
<li><b>[username]:</b> Benutzername</li>
<li><b>[userFirstName]:</b> Vorname des Benutzers (falls vorhanden)</li>
<li><b>[userLastName]:</b> Nachname des Benutzers (falls vorhanden)</li>
</ul>
]]></de>
<en><![CDATA[
<p>Content of the confirmation e-mail. Available variables:</p>
<ul>
<li><b>[host]:</b> Host of the project (system)</li>
<li><b>[userId]:</b> User id of the user</li>
<li><b>[email]:</b> E mail of the user</li>
<li><b>[confirmLink]:</b> Confirmation link (must be included!)</li>
<li><b>[username]:</b> Username</li>
<li><b>[userFirstName]:</b> First name of the user (if available)</li>
<li><b>[userLastName]:</b> Last name of the user (if available)</li>
</ul>
]]></en>
</locale>
<locale name="mail.text.changeEmail.title">
<de><![CDATA[Frontend Users: E-Mail ändern]]></de>
......@@ -2135,6 +2213,10 @@ The deletion of your user account on [host] was requested on [date]. Please conf
<de><![CDATA[Automatische Aktivierung]]></de>
<en><![CDATA[Auto activation]]></en>
</locale>
<locale name="controls.settings.registrars.template.activationModeOptionAutoWithEmailConfirm">
<de><![CDATA[Automatische Aktivierung (Link zur Bestätigung der E-Mail-Adresse wird trotzdem versandt)]]></de>
<en><![CDATA[Auto activation (link to confirm email address will be sent regardless)]]></en>
</locale>
<locale name="controls.settings.registrars.template.activationModeOptionManual">
<de><![CDATA[Manuelle Aktivierung (über Benutzer-Verwaltung)]]></de>
<en><![CDATA[Manual activation (via User Management)]]></en>
......
parameters:
ignoreErrors:
-
message: "#^Call to an undefined method QUI\\\\FrontendUsers\\\\Controls\\\\Profile\\\\ControlInterface\\:\\:setAttribute\\(\\)\\.$#"
count: 1
path: ajax/frontend/profile/save.php
-
message: "#^Parameter \\#2 \\$code of class QUI\\\\FrontendUsers\\\\Exception constructor expects int, string given\\.$#"
count: 1
path: ajax/frontend/profile/save.php
-
message: "#^Variable \\$Registrar in PHPDoc tag @var does not match any variable in the foreach loop\\: \\$class$#"
count: 1
path: ajax/settings/getAuthenticators.php
-
message: "#^PHPDoc tag @return with type mixed is not subtype of native type string\\.$#"
count: 1
path: src/QUI/FrontendUsers/AbstractRegistrar.php
-
message: "#^Parameter \\#1 \\$User of static method QUI\\\\FrontendUsers\\\\Utils\\:\\:setUserEmailVerified\\(\\) expects QUI\\\\Users\\\\User, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
count: 1
path: src/QUI/FrontendUsers/ActivationVerification.php
-
message: "#^Parameter \\#1 \\$code of method QUI\\\\Interfaces\\\\Users\\\\User\\:\\:activate\\(\\) expects string, false given\\.$#"
count: 1
path: src/QUI/FrontendUsers/ActivationVerification.php
-
message: "#^Negated boolean expression is always true\\.$#"
count: 1
path: src/QUI/FrontendUsers/Console/SendUserMails.php
-
message: "#^Parameter \\#1 \\$groupId of method QUI\\\\Interfaces\\\\Users\\\\User\\:\\:addToGroup\\(\\) expects int, string given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Console/SetUserGroups.php
-
message: "#^Instantiated class QUI\\\\ERP\\\\Order\\\\Exception not found\\.$#"
count: 6
path: src/QUI/FrontendUsers/Controls/Address/Address.php
-
message: "#^PHPDoc tag @throws with type QUI\\\\ERP\\\\Order\\\\Exception is not subtype of Throwable$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Address/Address.php
-
message: "#^Throwing object of an unknown class QUI\\\\ERP\\\\Order\\\\Exception\\.$#"
count: 6
path: src/QUI/FrontendUsers/Controls/Address/Address.php
-
message: "#^Variable \\$Authenticator in PHPDoc tag @var does not exist\\.$#"
count: 2
path: src/QUI/FrontendUsers/Controls/Login.php
-
message: "#^Call to an undefined method QUI\\\\FrontendUsers\\\\Controls\\\\Profile\\\\ControlInterface\\:\\:setAttribute\\(\\)\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Profile.php
-
message: "#^Parameter \\#1 \\$maxWidth of method QUI\\\\Projects\\\\Media\\\\ExternalImage\\:\\:getSizeCacheUrl\\(\\) expects bool, int given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Profile/UserAvatar.php
-
message: "#^Parameter \\#2 \\$maxHeight of method QUI\\\\Projects\\\\Media\\\\ExternalImage\\:\\:getSizeCacheUrl\\(\\) expects bool, int given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Profile/UserAvatar.php
-
message: "#^Call to an undefined method QUI\\\\Interfaces\\\\Projects\\\\Media\\\\File\\:\\:setTitle\\(\\)\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Profile/UserAvatarUpload.php
-
message: "#^Parameter \\#1 \\$User of method QUI\\\\FrontendUsers\\\\Handler\\:\\:sendChangeEmailAddressMail\\(\\) expects QUI\\\\Users\\\\User, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Profile/UserData.php
-
message: "#^Parameter \\#1 \\$code of method QUI\\\\Interfaces\\\\Users\\\\User\\:\\:activate\\(\\) expects string, false given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Registration.php
-
message: "#^Parameter \\#1 \\$groupId of method QUI\\\\Interfaces\\\\Users\\\\User\\:\\:addToGroup\\(\\) expects int, string given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/Registration.php
-
message: "#^Parameter \\#1 \\$maxWidth of method QUI\\\\Projects\\\\Media\\\\ExternalImage\\:\\:getSizeCacheUrl\\(\\) expects bool, int given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/UserIcon.php
-
message: "#^Parameter \\#2 \\$maxHeight of method QUI\\\\Projects\\\\Media\\\\ExternalImage\\:\\:getSizeCacheUrl\\(\\) expects bool, int given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Controls/UserIcon.php
-
message: "#^Call to an undefined method QUI\\\\Interfaces\\\\Projects\\\\Site\\:\\:getLocation\\(\\)\\.$#"
count: 1
path: src/QUI/FrontendUsers/Events.php
-
message: "#^Call to method createResponse\\(\\) on an unknown class QUI\\\\REST\\\\ResponseFactory\\.$#"
count: 1
path: src/QUI/FrontendUsers/Rest/Routes/GetRegisterRequiredFields.php
-
message: "#^Instantiated class QUI\\\\REST\\\\ResponseFactory not found\\.$#"
count: 1
path: src/QUI/FrontendUsers/Rest/Routes/GetRegisterRequiredFields.php
-
message: "#^Parameter \\#1 \\$groupId of method QUI\\\\Interfaces\\\\Users\\\\User\\:\\:addToGroup\\(\\) expects int, string given\\.$#"
count: 1
path: src/QUI/FrontendUsers/Rest/Routes/PostRegister.php
......@@ -2,11 +2,16 @@ includes:
- phpstan-baseline.neon
parameters:
level: 1
level: 5
paths:
- src
- ajax
- types
excludePaths:
# Ignore files that use classes from optional packages
- src/QUI/FrontendUsers/ErpProvider.php
- src/QUI/FrontendUsers/Rest/Provider.php
- src/QUI/FrontendUsers/GdprDataProvider.php
bootstrapFiles:
- tests/phpstan-bootstrap.php
treatPhpDocTypesAsCertain: false
......
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/phpunit-bootstrap.php">
<testsuites>
<testsuite name="Tests">
<directory>tests/</directory>
</testsuite>
</testsuites>
</phpunit>
......@@ -180,7 +180,9 @@ public function getBody(): string
} catch (Exception $Exception) {
QUI\System\Log::writeException($Exception);
}
} elseif (!empty($registrationSettings['autoRedirectOnSuccess'][$projectLang])) {
}
if (!$redirectUrl && !empty($registrationSettings['autoRedirectOnSuccess'][$projectLang])) {
// show success message and redirect after 10 seconds
try {
$RedirectSite = QUI\Projects\Site\Utils::getSiteByLink(
......@@ -551,9 +553,18 @@ public function register()
break;
case $RegistrarHandler::ACTIVATION_MODE_AUTO:
case $RegistrarHandler::ACTIVATION_MODE_AUTO_WITH_EMAIL_CONFIRM:
if (!$NewUser->isActive()) {
$NewUser->activate(false, $SystemUser);
}
if ($registrarSettings['activationMode'] == $RegistrarHandler::ACTIVATION_MODE_AUTO_WITH_EMAIL_CONFIRM) {
$RegistrarHandler->sendEmailConfirmationMail(
$NewUser,
$NewUser->getAttribute('email'),
$Registrar->getProject()
);
}
break;
}
......
<?php
namespace QUI\FrontendUsers;
use QUI;
use QUI\Exception;
use QUI\Verification\AbstractVerification;
/**
* User verification to confirm an e-mail-address
*/
class EmailVerification extends AbstractVerification
{
/**
* Get the duration of a Verification (minutes)
*
* @return int - duration in minutes;
* if this method returns false use the module setting default value
* @throws Exception
*/
public function getValidDuration(): int
{
$settings = Handler::getInstance()->getMailSettings();
return (int)$settings['verificationValidityDuration'];
}
/**
* Execute this method on successful verification
*
* @return void
* @throws \Exception
*/
public function onSuccess(): void
{
$userId = $this->getIdentifier();
try {
$User = QUI::getUsers()->get($userId);
$email = $this->additionalData['email'];
Utils::setEmailAddressAsVerfifiedForUser($email, $User);
} catch (\Exception $Exception) {
QUI\System\Log::writeException($Exception);
throw $Exception;
}
}
/**
* Execute this method on unsuccessful verification
*
* @return void
*/
public function onError(): void
{
// nothing
}
/**
* This message is displayed to the user on successful verification
*
* @return string
*/
public function getSuccessMessage(): string
{
return '';
}
/**
* This message is displayed to the user on unsuccessful verification
*
* @param string $reason - The reason for the error (see \QUI\Verification\Verifier::REASON_)
* @return string
*/
public function getErrorMessage(string $reason): string
{
return '';
}
/**
* Automatically redirect the user to this URL on successful verification
*
* @return string|false - If this method returns false, no redirection takes place
* @throws Exception
*/
public function getOnSuccessRedirectUrl(): bool|string
{
$RegistrationSite = Handler::getInstance()->getRegistrationSignUpSite(
$this->getProject()
);
if (!$RegistrationSite) {
return false;
}
return $RegistrationSite->getUrlRewritten([], [
'success' => 'emailconfirm'
]);
}
/**
* Automatically redirect the user to this URL on unsuccessful verification
*
* @return string|false - If this method returns false, no redirection takes place
* @throws Exception
*/
public function getOnErrorRedirectUrl(): bool|string
{
$RegistrationSite = Handler::getInstance()->getRegistrationSignUpSite(
$this->getProject()
);
if (!$RegistrationSite) {
return false;
}
return $RegistrationSite->getUrlRewritten([], [
'error' => 'emailconfirm'
]);
}
/**
* Get the Project this Verification is intended for
*
* @return QUI\Projects\Project
* @throws Exception
*/
protected function getProject(): QUI\Projects\Project
{
$additionalData = $this->getAdditionalData();
return QUI::getProjectManager()->getProject(
$additionalData['project'],
$additionalData['projectLang']
);
}
}
......@@ -54,6 +54,23 @@ public static function getMailLocale(): array
'content.description' => ['quiqqer/frontend-users', 'mail.registration_activation.body.description']
],
[
'title' => QUI::getLocale()->get(
'quiqqer/frontend-users',
'mail.text.confirmEmail.title'
),
'description' => QUI::getLocale()->get(
'quiqqer/frontend-users',
'mail.text.confirmEmail.description'
),
'subject' => ['quiqqer/frontend-users', 'mail.confirm_email_address.subject'],
'content' => ['quiqqer/frontend-users', 'mail.confirm_email_address.body'],
'subject.description' => ['quiqqer/frontend-users', 'mail.confirm_email_address.subject.description'],
'content.description' => ['quiqqer/frontend-users', 'mail.confirm_email_address.body.description']
],
[
'title' => QUI::getLocale()->get(
'quiqqer/frontend-users',
......
<?php
namespace QUI\FrontendUsers\Exception;
use QUI\FrontendUsers\Exception;
class EmailAddressNotVerifiableException extends Exception
{
protected $code = 50002;
}
<?php
/**
* This file contains QUI\FrontendUsers\Handler
*/
namespace QUI\FrontendUsers;
use QUI;
use QUI\Mail\Mailer;
use QUI\Utils\Singleton;
use QUI\Verification\Verifier;
use QUI\Interfaces\Users\User as QUIUserInterface;
use function array_filter;
use function time;
/**
* Class Registration Handling
......@@ -33,6 +31,7 @@ class Handler extends Singleton
*/
const ACTIVATION_MODE_MAIL = 'mail';
const ACTIVATION_MODE_AUTO = 'auto';
const ACTIVATION_MODE_AUTO_WITH_EMAIL_CONFIRM = 'autoWithEmailConfirm';
const ACTIVATION_MODE_MANUAL = 'manual';
/**
......@@ -75,6 +74,7 @@ class Handler extends Singleton
const USER_ATTR_REGISTRAR = 'quiqqer.frontendUsers.registrar';
const USER_ATTR_ACTIVATION_LOGIN_EXECUTED = 'quiqqer.frontendUsers.activationLoginExecuted';
const USER_ATTR_EMAIL_VERIFIED = 'quiqqer.frontendUsers.emailVerified';
const USER_ATTR_EMAIL_ADDRESSES_VERIFIED = 'quiqqer.frontendUsers.emailAddressesVerified';
const USER_ATTR_USER_ACTIVATION_REQUIRED = 'quiqqer.frontendUsers.userActivationRequired';
/**
......@@ -632,7 +632,65 @@ public function sendChangeEmailAddressMail(
'username' => $User->getUsername(),
'userFirstName' => $User->getAttribute('firstname') ?: '',
'userLastName' => $User->getAttribute('lastname') ?: '',
'newEmail' => $newEmail,
'email' => $newEmail,
'date' => $L->formatDate(time()),
'confirmLink' => $confirmLink
])
]
);
} catch (\Exception $Exception) {
QUI\System\Log::addError(
self::class . ' :: sendChangeEmailAddressMail -> Send mail failed'
);
QUI\System\Log::writeException($Exception);
}
}
/**
* Send email to confirm an email address.
*
* @param QUIUserInterface $User
* @param string $email - New E-Mail-Adress
* @param QUI\Projects\Project $Project - The QUIQQER Project where the change action took place
* @return void
*
* @throws QUI\Exception
*/
public function sendEmailConfirmationMail(
QUIUserInterface $User,
string $email,
QUI\Projects\Project $Project
): void {
$EmailConfirmVerification = new EmailVerification($User->getUUID(), [
'project' => $Project->getName(),
'projectLang' => $Project->getLang(),
'email' => $email
]);
$confirmLink = Verifier::startVerification($EmailConfirmVerification, true);
$L = QUI::getLocale();
$lg = 'quiqqer/frontend-users';
$tplDir = QUI::getPackage('quiqqer/frontend-users')->getDir() . 'templates/';
$host = $Project->getVHost();
try {
$this->sendMail(
[
'subject' => $L->get($lg, 'mail.confirm_email_address.subject')
],
[
$email
],
$tplDir . 'mail.confirm_email_address.html',
[
'body' => $L->get($lg, 'mail.confirm_email_address.body', [
'host' => $host,
'userId' => $User->getUUID(),
'username' => $User->getUsername(),
'userFirstName' => $User->getAttribute('firstname') ?: '',
'userLastName' => $User->getAttribute('lastname') ?: '',
'email' => $email,
'date' => $L->formatDate(time()),
'confirmLink' => $confirmLink
])
......
<?php
/**
* This file contains QUI\FrontendUsers\Utils
*/
namespace QUI\FrontendUsers;
use QUI;
use QUI\FrontendUsers\Controls\Profile\ControlInterface;
use QUI\Package\Package;
use QUI\Permissions;
use QUI\Interfaces\Users\User as QUIUserInterface;
use QUI\FrontendUsers\Exception\EmailAddressNotVerifiableException;
use function class_exists;
use function in_array;
use function is_a;
use function json_decode;
......@@ -347,8 +346,10 @@ public static function loadTranslationForCategories(array $categories = []): arr
* @param null|QUI\Projects\Project $Project
* @return array
*/
public static function setUrlsToCategorySettings(array $categories = [], QUI\Projects\Project $Project = null): array
{
public static function setUrlsToCategorySettings(
array $categories = [],
QUI\Projects\Project $Project = null
): array {
try {
if ($Project === null) {
$Project = QUI::getRewrite()->getProject();
......@@ -426,12 +427,24 @@ public static function getGravatarUrl(string $email, int $s = 80): string
}
/**
* Check if the standard e-mail address of a user is verified
* Check if the STANDARD e-mail address of a user is verified
*
* @param QUI\Users\User $User
* @param QUIUserInterface $User
* @return bool
* @deprecated use isDefaultUserEmailVerified
*/
public static function isUserEmailVerified(QUI\Users\User $User): bool
public static function isUserEmailVerified(QUIUserInterface $User): bool
{
return self::isDefaultUserEmailVerified($User);
}
/**
* Check if the STANDARD e-mail address of a user is verified
*
* @param QUIUserInterface $User
* @return bool
*/
public static function isDefaultUserEmailVerified(QUIUserInterface $User): bool
{
$email = $User->getAttribute('email');
......@@ -442,21 +455,124 @@ public static function isUserEmailVerified(QUI\Users\User $User): bool
return $User->getAttribute(Handler::USER_ATTR_EMAIL_VERIFIED);
}
/**
* Check if any e-mail address (user, user address) is verified for a specific user.
*
* @param string $email
* @param QUIUserInterface $User
* @return bool
*/
public static function isEmailAddressVerifiedForUser(string $email, QUIUserInterface $User): bool
{
$verifiedEmailAddresses = $User->getAttribute(Handler::USER_ATTR_EMAIL_ADDRESSES_VERIFIED);
if (empty($verifiedEmailAddresses)) {
return false;
}
return in_array($email, $verifiedEmailAddresses);
}
/**
* Set a specific email address as verified for a user.
*
* @param string $email
* @param QUIUserInterface $User
* @return void
*
* @throws EmailAddressNotVerifiableException
*/
public static function setEmailAddressAsVerfifiedForUser(string $email, QUIUserInterface $User): void
{
if (self::isEmailAddressVerifiedForUser($email, $User)) {
return;
}
if (empty($email)) {
throw new EmailAddressNotVerifiableException('Cannot verify empty email address.');
}
if (!QUI\Utils\Security\Orthos::checkMailSyntax($email)) {
throw new EmailAddressNotVerifiableException("Cannot verify invalid email address $email.");
}
if (!self::doesUserHaveEmailAddress($email, $User)) {
throw new EmailAddressNotVerifiableException(
"Cannot verify email address $email for user {$User->getId()}, because this email address"
. " is not associated with this user (neither saved in user or user addresses)."
);
}
$verifiedEmailAddresses = $User->getAttribute(Handler::USER_ATTR_EMAIL_ADDRESSES_VERIFIED);
if (empty($verifiedEmailAddresses)) {
$verifiedEmailAddresses = [];
}
$verifiedEmailAddresses[] = $email;
$User->setAttribute(Handler::USER_ATTR_EMAIL_ADDRESSES_VERIFIED, $verifiedEmailAddresses);
$User->save(QUI::getUsers()->getSystemUser());
}
/**
* Check if a user has a specific email address (either in user or one of user addresses).
*
* @param string $email
* @param QUIUserInterface $User
* @return bool
*/
public static function doesUserHaveEmailAddress(string $email, QUIUserInterface $User): bool
{
$userEmail = $User->getAttribute('email');
if ($email === $userEmail) {
return true;
}
foreach ($User->getAddressList() as $Address) {
if (!($Address instanceof QUI\Users\Address)) {
continue;
}
$addressEmails = $Address->getMailList();
if (in_array($email, $addressEmails)) {
return true;
}
}
return false;
}
/**
* Set the standard e-mail address of a user to status "verified"
*
* @param QUI\Users\User $User
* @param QUIUserInterface $User
* @return void
* @throws EmailAddressNotVerifiableException
* @deprecated use setDefaultUserEmailVerified
*/
public static function setUserEmailVerified(QUIUserInterface $User): void
{
self::setDefaultUserEmailVerified($User);
}
/**
* Set the standard e-mail address of a user to status "verified"
*
* @throws QUI\Exception
* @param QUIUserInterface $User
* @return void
* @throws EmailAddressNotVerifiableException
*/
public static function setUserEmailVerified(QUI\Users\User $User): void
public static function setDefaultUserEmailVerified(QUIUserInterface $User): void
{
self::setEmailAddressAsVerfifiedForUser($User->getAttribute('email'), $User);
$User->setAttribute(Handler::USER_ATTR_EMAIL_VERIFIED, true);
$User->save(QUI::getUsers()->getSystemUser());
}
public static function getMissingAddressFields(QUI\Users\Address $Address): array
{
$missing = [];
......