Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fusion support #63

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.idea
.DS_Store
43 changes: 43 additions & 0 deletions Classes/EelHelper/AuthenticationHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Sandstorm\UserManagement\EelHelper;
use Neos\Eel\ProtectedContextAwareInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Security\Context as SecurityContext;

class AuthenticationHelper implements ProtectedContextAwareInterface {

/**
* @Flow\Inject
* @var SecurityContext
*/
protected $securityContext;

/**
* Check wheather an user is authenticated against an specific authenticationprovider
*
* @param string $authenticationProviderName
* @return boolean
*/
public function isAuthenticated(string $authenticationProviderName): bool{
$activeTokens = $this->securityContext->getAuthenticationTokens();
foreach ($activeTokens as $token) {
if ($token->getAuthenticationProviderName() === $authenticationProviderName && $token->isAuthenticated()) {
return true;
}
}
return false;
}


/**
* All methods are considered safe
*
* @param string $methodName
* @return boolean
*/
public function allowsCallOfMethod($methodName):bool
{
return true;
}
}
3 changes: 3 additions & 0 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ Sandstorm:
address: '[email protected]'

Neos:
Fusion:
defaultContext:
'Sandstorm.UserManagement': 'Sandstorm\UserManagement\EelHelper\AuthenticationHelper'
Flow:
mvc:
routes:
Expand Down
92 changes: 92 additions & 0 deletions Configuration/Views.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,95 @@
requestFilter: 'mainRequest.isPackage("Neos.Neos") && isPackage("Sandstorm.UserManagement")'
options:
layoutRootPaths: ['resource://Sandstorm.UserManagement/Private/Layouts/Neos']
###
#
# All controller actions are overwritten here to have minimal change on the controller logic, therefore achive backwards compatibilty with legacy fusion templates
#
###


# Login related actions
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("Login") && isAction("login")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: loginSite
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("Login") && isAction("authenticate")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: authenticationSite

# Registration related actions
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("Registration") && isAction("index")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: registrationIndexSite
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("Registration") && isAction("register")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: registrationSubmitSite
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("Registration") && isAction("activateAccount")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: registrationActivateAccountSite
# Password Reset related actions
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("ResetPassword") && isAction("index")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: resetPasswordIndexSite
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("ResetPassword") && isAction("insertNewPassword")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: resetPasswordSetPasswordSite
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("ResetPassword") && isAction("requestToken")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: resetPasswordEmailSentSite
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("ResetPassword") && isAction("updatePassword")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
fusionPath: resetPasswordSuccessfulSite
68 changes: 62 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This package works in Neos CMS and Flow and provides the following functionality
* Sending out an e-mail for account confirmation
* Login of registered (frontend) users via a login form
* "Forgotten password" with password reset e-mail
* Custom Site/E-Mail Templates (Site templates also in fusion)

# 1. Compatibility and Maintenance
Sandstorm.UserManagement is currently being maintained for the following versions:
Expand Down Expand Up @@ -235,8 +236,18 @@ Sandstorm\UserManagement\Domain\Service\RedirectTargetServiceInterface:
```

## Checking for a logged-in user in your templates
### Fusion (Recommended)
The UserManagement Package now supports Fusion!
To check if a user is logged in, a simple [Eel-Helper](./Classes/EelHelper/AuthenticationHelper.php) can be used as follows:
```
prototype(Your.Vendor:Component) < prototype(Neos.Fusion:Component) {
isAuthenticated = ${Sandstorm.UserManagement.isAuthenticated('Sandstorm.UserManagement:Login')}
renderer = afx `
<p>Is user authenticated: {props.isAuthenticated ? 'true' : 'false'}</p>
`
```
### Fluid (Legacy)
There is a ViewHelper available that allows you to check if somebody is logged into the frontend. Here's an example:

```
{namespace um=Sandstorm\UserManagement\ViewHelpers}

Expand All @@ -260,7 +271,30 @@ argument to which you can pass the name of the Auth Provider you are using.
You can change any template via the default method using `Views.yaml`. Please see
http://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/ModelViewController.html#configuring-views-through-views-yaml.
Here's an example how to plug your own login template:

### Fusion (Recommended)
If you just want to apply simple modifications to the way the components are rendered, or which classes should be added to which HTML tags, override the responsible [presentation components](./Resources/Private/Fusion/Presentation/). This can be done like this:
```fusion
prototype(Sandstorm.UserManagement:Component.LoginForm) < prototype(Neos.Fusion:Component) {
passwordResetUri >
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to clear the renderer not the passwordResetUri

renderer = afx`
<p>Your custom loginform here.</p>
<a href={props.passwordResetUri}>click here to reset your password.</a>
`
}
```
To overwrite the fusion paths directly, in order to implement complete custom fusion, you can overwrite the `fusionPath` property as follows:
```YAML
-
requestFilter: 'isPackage("Sandstorm.UserManagement") && isController("Login") && isAction("login")'
viewObjectName: 'Neos\Fusion\View\FusionView'
options:
fusionPathPatterns:
- resource://Neos.Fusion/Private/Fusion/Root.fusion
- resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
- resource://Sandstorm.UserManagement/Private/Fusion/Root.fusion
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of Sandstorm.UserManagement -> Your.Vendor

fusionPath: yourCustomFusionPath
```
### Fluid (Legacy)
```YAML

-
Expand Down Expand Up @@ -380,12 +414,34 @@ Feel free to submit issues/PRs :)
# 6. TODOs

* More Tests.
* Translations

# 7. FAQ

* *What happens if the user did not receive the registration email?*
Just tell the user to register again. In this case, previous unfinished registrations are discarded.
## Fusion Support
- Full support for the default NodeTypes as follows:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default NodeTypes -> shipped/included NodeTypes

- POC: migrate all fluid templates & overwrite them using the corresponding actions in the `Views.yaml`
- Ideally, most of the controller logic is obsolete in further releases and can be implemented in pure fusion or custom fusion components
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

controller logic -> render controller logic


# 7. FAQ
## What happens if the user did not receive the registration email?
Just tell the user to register again. In this case, previous unfinished registrations are discarded.

## Why didn't you use X to implement fusion support?
Copy link
Author

@codecrafter404 codecrafter404 Aug 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are all render controller actions overwritten in the Views.yaml to implement fusion support?

We thought quite a bit about the ideal implementation for this change. It should meet the following requirements:
- Easy to use
- Least modifications as possible
- Backwards compatible, or at least minimal work should be done to use the legacy fluid templates
The following solutions crossed our mind:
- Overwrite everything in the `Root.fusion`
- PRO: straightforward
- CON: it would be a 'hacky' solution and bound to break in the near future
- Update the controller logic to render a `FusionView`
- PRO: we can render Fusion & add context based on the current route
- CON: Every controller would need to be updated; only with a lot of work backwards compatible would be archivable
- Overwrite specific controller actions in the `Views.yaml`
- PRO: this mechanism is already used to overwrite the default template; doesn't need a lot of modification of the controller logic; can be gradually migrated
- CON: requires small modifications to existing projects in order to further use legacy fluid templates

Therefore, we settled with the last approach and until now it works flawlessly.
# 8. License
MIT.
https://opensource.org/licenses/MIT
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find a better Naming convention, when the NodeTypes have been reworked

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
prototype(Sandstorm.UserManagement:Content.Login) < prototype(Neos.Fusion:Component) {
account = ''
isAuthenticated = ${Sandstorm.UserManagement.isAuthenticated('Sandstorm.UserManagement:Login')}
renderer = Sandstorm.UserManagement:Component.Login {
account = ${props.account}
isAuthenticated = ${props.isAuthenticated}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
prototype(Sandstorm.UserManagement:Content.LoginForm) < prototype(Neos.Fusion:Component) {
passwordResetUri = Neos.Fusion:UriBuilder {
package = "Sandstorm.UserManagement"
controller = "ResetPassword"
action = "index"
}
renderer = Sandstorm.UserManagement:Component.LoginForm {
passwordResetUri = ${props.passwordResetUri}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
prototype(Sandstorm.UserManagement:Content.RegistrationAccountActivation) < prototype(Neos.Fusion:Component) {

// all worked
success = true
// if set, the auth token was not found.
tokenNotFound = false
// if set, the token had a timeout.
tokenTimeout = false

@private {
indexLink = Neos.Fusion:UriBuilder {
package = "Sandstorm.UserManagement"
controller = "Registration"
action = "index"
}
}

renderer = Sandstorm.UserManagement:Component.RegistrationAccountActivation {
success = ${props.success}
tokenNotFound = ${props.tokenNotFound}
tokenTimeout = ${props.tokenTimeout}

indexLink = ${private.indexLink}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
prototype(Sandstorm.UserManagement:Content.Register.Index) < prototype(Neos.Fusion:Component) {
isAuthenticated = ${Sandstorm.UserManagement.isAuthenticated('Sandstorm.UserManagement:Login')}
renderer = Sandstorm.UserManagement:Component.Register.Index {
isAuthenticated = ${props.isAuthenticated}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
prototype(Sandstorm.UserManagement:Content.ResetPassword.SetPassword) < prototype(Neos.Fusion:Component) {

// all worked
success = true
// if set, the auth token was not found.
tokenNotFound = false
// if set, the token had a timeout.
tokenTimeout = false

resetPasswordFlow = ''

@private {
indexLink = Neos.Fusion:UriBuilder {
package = "Sandstorm.UserManagement"
controller = "ResetPassword"
action = "index"
}
}

renderer = Sandstorm.UserManagement:Component.ResetPassword.SetPassword {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use @apply.props=${props}

success = ${props.success}
tokenNotFound = ${props.tokenNotFound}
tokenTimeout = ${props.tokenTimeout}

indexLink = ${private.indexLink}

resetPasswordFlow = ${props.resetPasswordFlow}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
prototype(Sandstorm.UserManagement:Content.ResetPassword.Successful) < prototype(Neos.Fusion:Component) {

success = true
accountNotFound = false

@private {
loginLink = Neos.Fusion:UriBuilder {
package = "Sandstorm.UserManagement"
controller = "Login"
action = "login"
}
indexLink = Neos.Fusion:UriBuilder {
package = "Sandstorm.UserManagement"
controller = "ResetPassword"
action = "index"
}
}

renderer = Sandstorm.UserManagement:Component.ResetPassword.Successful {
success = ${props.success}
accountNotFound = ${props.accountNotFound}

loginLink = ${private.loginLink}
indexLink = ${private.indexLink}
}
}
Copy link
Author

@codecrafter404 codecrafter404 Aug 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update Naming

rename Sites to Routes

rename Content.< Sitename > to Route.< Sitename >

and move all routes into one big /Resources/Private/Fusion/RoutePaths.fusion

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
authenticationSite = Sandstorm.UserManagement:SiteLayout {
title = 'Login'
content = Sandstorm.UserManagement:Authentication {
account = ${account}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
loginSite = Sandstorm.UserManagement:SiteLayout {
title = 'Login'
content = Sandstorm.UserManagement:Content.Login {
account = ${account}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
registrationActivateAccountSite = Sandstorm.UserManagement:SiteLayout {
title = 'Activate Account'
content = Sandstorm.UserManagement:Content.RegistrationAccountActivation {
success = ${success}
tokenNotFound = ${tokenNotFound}
tokenTimeout = ${tokenTimeout}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
registrationIndexSite = Sandstorm.UserManagement:SiteLayout {
title = 'Registration'
content = Sandstorm.UserManagement:Content.Register.Index {
account = ${account}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
registrationSubmitSite = Sandstorm.UserManagement:SiteLayout {
title = 'Registration'
content = Sandstorm.UserManagement:Component.RegisterSubmit {
registrationFlow = ${registrationFlow}
}
}

Loading