Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Add frontend user authentication and document restriction to pimcore.

| Release | Supported Pimcore Versions | Supported Symfony Versions | Release Date | Maintained | Branch |
|---------|-----------------------------------|----------------------------|--------------|----------------|----------|
| **5.x** | `11.0` | `6.2` | 28.09.2023 | Feature Branch | master |
| **5.x** | `11.0` | `6.4` | 28.09.2023 | Feature Branch | master |
| **4.x** | `10.5 - 10.6` | `5.4` | 22.11.2021 | Unsupported | 4.x |
| **3.x** | `6.0` - `6.8` | `3.4`, `^4.4` | 21.07.2019 | Unsupported | 3.x |
| **2.5** | `5.4`, `5.5`, `5.6`, `5.7`, `5.8` | `3.4` | 18.07.2019 | Unsupported | 2.5 |
Expand All @@ -32,7 +32,7 @@ Please read the installation instructions before going deep with Members!

```json
"require" : {
"dachcom-digital/members" : "~5.1.0"
"dachcom-digital/members" : "~5.2.0"
}
```

Expand Down Expand Up @@ -167,6 +167,6 @@ Before updating, please [check our upgrade notes!](UPGRADE.md)
## License
**DACHCOM.DIGITAL AG**, Löwenhofstrasse 15, 9424 Rheineck, Schweiz
[dachcom.com](https://www.dachcom.com), dcdi@dachcom.ch
Copyright © 2024 DACHCOM.DIGITAL. All rights reserved.
Copyright © 2025 DACHCOM.DIGITAL. All rights reserved.

For licensing details please visit [LICENSE.md](LICENSE.md)
4 changes: 4 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Upgrade Notes

## 5.1.0
- [NEW FEATURE] "Preview confirmation" workflow added to avoid registration confirmation by prefetching email processes.
Read more about it [here](./docs/60_RegistrationTypes.md#email-prefetching).
This also comes with a new template: `@Members/registration/confirm_preview.html.twig` and also two new translations (
`members.registration.confirm_preview`, `members.registration.complete_confirmation`)
- [LICENSE] Dual-License with GPL and Dachcom Commercial License (DCL) added

### 5.0.3
Expand Down
2 changes: 2 additions & 0 deletions config/install/translations/frontend.csv
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"members.registration.confirmed","Glückwunsch %username%, Ihr Benutzerkonto ist jetzt bestätigt.","Congrats %username%, your account is now activated."
"members.registration.already_confirmed_or_not_found","Dieses Benutzerkonto wurde bereits bestätigt oder existiert nicht.","This user account has already been confirmed or does not exist."
"members.registration.back","Zurück zur ursprünglichen Seite.","Back to the originating page."
"members.registration.confirm_preview","Hallo %username%, bitte bestätige nun deine Registrierung!","Hello %username%, please confirm your registration now!"
"members.registration.complete_confirmation","Registrierung abschliessen","Complete registration"
"members.registration.submit","Registrieren","Register"
"members.registration.flash.user_created","Der Benutzer wurde erfolgreich erstellt.","The user has been created successfully."
"members.resetting.check_email","Eine E-Mail wurde verschickt. Sie beinhaltet einen Link zum Zurücksetzen des Passwortes. Hinweis: Ein neues Passwort kann nur alle %tokenLifetime% Stunden beantragt werden. Eventuell wurde diese E-Mail als Spam markiert, wenn sie nicht angekommen ist.","An email has been sent. It contains a link you must click to reset your password. Note: You can only request a new password once within %tokenLifetime% hours. If you don't get an email check your spam folder or try again."
Expand Down
4 changes: 4 additions & 0 deletions config/pimcore/routing/registration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ members_user_registration_check_admin:
path: /check-admin
defaults: { _controller: MembersBundle\Controller\RegistrationController::checkAdminAction }
methods: [GET]
members_user_registration_confirm_preview:
path: /confirm-preview/{token}
defaults: { _controller: MembersBundle\Controller\RegistrationController::confirmPreviewAction }
methods: [ GET ]
members_user_registration_confirm:
path: /confirm/{token}
defaults: { _controller: MembersBundle\Controller\RegistrationController::confirmAction }
Expand Down
31 changes: 30 additions & 1 deletion docs/60_RegistrationTypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,49 @@ Name: `confirm_by_mail`

> This is the default value.

After registration the user will receive a confirmation mail with a confirmation url. By clicking on that link the user gets automatically activated.
After registration the user will receive a confirmation mail with a confirmation url.
By clicking on that link the user gets automatically activated.

If `send_admin_mail_after_register` is enabled, the system will send a notification mail to a defined admin.

#### Email prefetching

> [!IMPORTANT]
> Some email providers have spam detection or security features that prefetch URLs from incoming emails
> (e.g., Safe Links in Microsoft Defender for Office 365).

To prevent unintended automatic activations, you can enable a "preview confirmation" page.
This requires users to manually confirm their registration by clicking an additional button.

This feature is disabled by default. To enable it, update your configuration as follows:

```yaml

members:
enable_preview_confirmation: true # default is false
```

When enabled, users will first be redirected to /confirm-preview/{token},
where they must confirm their registration manually.

***

### Confirm By Admin
Name: `confirm_by_admin`

After registration the user has to wait until a authorized admin activates the user in backend.

If `send_user_mail_after_confirmed` is enabled, the system will send a notification mail to user.

***

### Confirm Instant
Name: `confirm_instant`

After registration the user gets automatically logged in without any further actions.

***

## Configuration
Add those lines to your `config/config.yaml`:

Expand All @@ -37,6 +64,8 @@ members:
send_user_mail_after_confirmed: false
```

***

## Registration Types with SSO
If you're using the [SSO feature](./SSO/10_Overview.md), you may want to define some independent mail workflows.
If Members detects an SSO registration process, you're able to define the registration type via the `post_register_type_oauth` flag.
Expand Down
16 changes: 16 additions & 0 deletions src/Controller/RegistrationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ public function checkAdminAction(Request $request): Response
return $this->renderTemplate('@Members/registration/check_admin.html.twig', ['user' => $user]);
}

public function confirmPreviewAction(Request $request, string $token): Response
{
$user = $this->userManager->findUserByConfirmationToken($token);

if ($user === null) {
throw new NotFoundHttpException(sprintf('The user with confirmation token "%s" does not exist', $token));
}

$confirmationUrl = $this->generateUrl('members_user_registration_confirm', ['token' => $user->getConfirmationToken()]);

return $this->renderTemplate('@Members/registration/confirm_preview.html.twig', [
'user' => $user,
'confirmationUrl' => $confirmationUrl,
]);
}

public function confirmAction(Request $request, string $token): Response
{
$user = $this->userManager->findUserByConfirmationToken($token);
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function getConfigTreeBuilder()
->children()
->booleanNode('send_admin_mail_after_register')->defaultFalse()->end()
->booleanNode('send_user_mail_after_confirmed')->defaultFalse()->end()
->booleanNode('enable_preview_confirmation')->defaultFalse()->end()
->enumNode('post_register_type')
->values($validPostRegisterTypes)
->defaultValue('confirm_by_mail')
Expand Down
6 changes: 5 additions & 1 deletion src/Mailer/Mailer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ public function __construct(

public function sendConfirmationEmailMessage(UserInterface $user): void
{
$route = $this->configuration->getConfig('enable_preview_confirmation') === true
? 'members_user_registration_confirm_preview'
: 'members_user_registration_confirm';

$template = $this->getMailTemplatePath('register_confirm', $user);
$url = $this->router->generate('members_user_registration_confirm', ['token' => $user->getConfirmationToken()], UrlGeneratorInterface::ABSOLUTE_URL);
$url = $this->router->generate($route, ['token' => $user->getConfirmationToken()], UrlGeneratorInterface::ABSOLUTE_URL);

$mailParams = [
'user' => $user,
Expand Down
9 changes: 9 additions & 0 deletions templates/registration/confirm_preview.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends '@Members/layout.html.twig' %}

{% block members_user_content %}
{% set user_name = user is not null ? user.username|default(user.email) : '' %}
<p>{{ 'members.registration.confirm_preview'|trans({ '%username%': user_name }) }}</p>
{% if confirmationUrl %}
<p><a class="btn btn-info btn-sm" href="{{ confirmationUrl }}">{{ 'members.registration.complete_confirmation'|trans }}</a></p>
{% endif %}
{% endblock members_user_content %}
10 changes: 2 additions & 8 deletions tests/Unit/Config/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

class ConfigurationTest extends DachcomBundleTestCase
{
/**
* @throws \Codeception\Exception\ModuleException
*/
public function testConfigArrayGetter()
public function testConfigArrayGetter(): void
{
$configuration = $this->getContainer()->get(Configuration::class);
$adminConfig = $configuration->getConfigArray();
Expand All @@ -19,10 +16,7 @@ public function testConfigArrayGetter()
$this->assertArrayHasKey('send_admin_mail_after_register', $adminConfig);
}

/**
* @throws \Codeception\Exception\ModuleException
*/
public function testConfigSlotGetter()
public function testConfigSlotGetter(): void
{
$configuration = $this->getContainer()->get(Configuration::class);
$configSlot = $configuration->getConfig('post_register_type');
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Dao/GroupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class GroupTest extends DachcomBundleTestCase
/**
* @throws \Exception
*/
public function testGroupDaoEntity()
public function testGroupDaoEntity(): void
{
$group = $this->createUserGroup('group-1', ['ROLE_MEMBERS_MODERATOR']);
$storedGroup = MembersGroup::getById($group->getId(), ['force' => true]);
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Dao/SsoIdentityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class SsoIdentityTest extends DachcomBundleTestCase
/**
* @throws \Exception
*/
public function testSsoIdentityDaoEntity()
public function testSsoIdentityDaoEntity(): void
{
$ssoIdentity = $this->createSsoIdentity(true, 'google', '1234');

Expand Down
6 changes: 1 addition & 5 deletions tests/Unit/Dao/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@

class UserTest extends DachcomBundleTestCase
{
/**
* @throws \Codeception\Exception\ModuleException
* @throws \Exception
*/
public function testUserDaoEntity()
public function testUserDaoEntity(): void
{
$group1 = $this->createUserGroup('group-1');
$group2 = $this->createUserGroup('group-2');
Expand Down
20 changes: 4 additions & 16 deletions tests/Unit/Manager/ClassManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,31 @@

class ClassManagerTest extends DachcomBundleTestCase
{
/**
* @throws ModuleException
*/
public function testGroupClass()
public function testGroupClass(): void
{
$classManager = $this->getContainer()->get(ClassManager::class);
$groupClass = $classManager->getGroupClass();

$this->assertEquals(MembersGroup::class, $groupClass);
}

/**
* @throws ModuleException
*/
public function testGroupListing()
public function testGroupListing(): void
{
$classManager = $this->getContainer()->get(ClassManager::class);
$groupListing = $classManager->getGroupListing();

$this->assertInstanceOf(MembersGroup\Listing::class, $groupListing);
}

/**
* @throws ModuleException
*/
public function testUserClass()
public function testUserClass(): void
{
$classManager = $this->getContainer()->get(ClassManager::class);
$userClass = $classManager->getUserClass();

$this->assertEquals(MembersUser::class, $userClass);
}

/**
* @throws ModuleException
*/
public function testUserListing()
public function testUserListing(): void
{
$classManager = $this->getContainer()->get(ClassManager::class);
$userListing = $classManager->getUserListing();
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Manager/LoginManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private function mockUser(): UserInterface
$user
->expects($this->once())
->method('getRoles')
->will($this->returnValue(['ROLE_USER']));
->willReturn(['ROLE_USER']);

return $user;
}
Expand Down
6 changes: 3 additions & 3 deletions tests/Unit/Manager/RestrictionManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class RestrictionManagerTest extends DachcomBundleTestCase
{
public function testGetElementRestrictedGroupsDefault()
public function testGetElementRestrictedGroupsDefault(): void
{
$document = $this->createRestrictedDocument();
$restrictionManager = $this->getContainer()->get(RestrictionManager::class);
Expand All @@ -19,7 +19,7 @@ public function testGetElementRestrictedGroupsDefault()
$this->assertContains('default', $restrictionGroups);
}

public function testGetElementRestrictedGroups()
public function testGetElementRestrictedGroups(): void
{
$group = $this->createUserGroup();
$document = $this->createRestrictedDocument([$group->getId()]);
Expand All @@ -33,7 +33,7 @@ public function testGetElementRestrictedGroups()

}

public function testGetElementRestrictionStatus()
public function testGetElementRestrictionStatus(): void
{
$group = $this->createUserGroup();
$document = $this->createRestrictedDocument([$group->getId()]);
Expand Down
15 changes: 3 additions & 12 deletions tests/Unit/Manager/SsoIdentityManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@

class SsoIdentityManagerTest extends DachcomBundleTestCase
{
/**
* @throws \Exception
*/
public function testClassGetter()
public function testClassGetter(): void
{
$ssoIdentityManager = $this->getContainer()->get(SsoIdentityManager::class);
$ssoIdentityClass = $ssoIdentityManager->getClass();

$this->assertEquals(SsoIdentity::class, $ssoIdentityClass);
}

/**
* @throws \Exception
*/
public function testCreateNewSsoIdentity()
public function testCreateNewSsoIdentity(): void
{
$ssoIdentity = $this->createSsoIdentity(true, 'google', '1234');
$this->assertInstanceOf(SsoIdentityInterface::class, $ssoIdentity);
Expand All @@ -34,10 +28,7 @@ public function testCreateNewSsoIdentity()
$this->assertEquals($expectedKey, $ssoIdentity->getKey());
}

/**
* @throws \Exception
*/
public function testFindUserBySsoIdentity()
public function testFindUserBySsoIdentity(): void
{
$ssoIdentity = $this->createSsoIdentity(true, 'google', '1234');
$ssoIdentityManager = $this->getContainer()->get(SsoIdentityManager::class);
Expand Down
3 changes: 0 additions & 3 deletions tests/Unit/Manager/UserManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@

class UserManagerTest extends DachcomBundleTestCase
{
/**
* @throws \Codeception\Exception\ModuleException
*/
public function testClassGetter(): void
{
$userManager = $this->getContainer()->get(UserManager::class);
Expand Down
7 changes: 1 addition & 6 deletions tests/Unit/Security/RoleOptionsProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

class RoleOptionsProviderTest extends DachcomBundleTestCase
{
/**
* @throws \Codeception\Exception\ModuleException
*/
public function testRoleOptions()
public function testRoleOptions(): void
{
/** @var RoleOptionsProvider $roleOptionsProvider */
$roleOptionsProvider = $this->getContainer()->get(RoleOptionsProvider::class);
Expand All @@ -32,7 +29,5 @@ public function testRoleOptions()
$this->assertArrayHasKey('value', $options[1]);
$this->assertEquals('ROLE_MEMBERS_MODERATOR', $options[1]['key']);
$this->assertEquals('ROLE_MEMBERS_MODERATOR', $options[1]['value']);

}

}
Loading