Skip to content

Commit

Permalink
Implement backend redirection and notification confirmation
Browse files Browse the repository at this point in the history
  • Loading branch information
mficzel committed Nov 22, 2024
1 parent 29319e9 commit 67f4d37
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 79 deletions.
83 changes: 83 additions & 0 deletions Classes/Aspect/BackendRedirectionAspect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

namespace Sitegeist\GrapeVine\Aspect;

use Neos\Flow\Annotations as Flow;
use Neos\Flow\Aop\JoinPointInterface;
use Neos\Flow\Core\Bootstrap;
use Neos\Flow\Http\HttpRequestHandlerInterface;
use Neos\Flow\Mvc\ActionRequestFactory;
use Neos\Flow\Mvc\Routing\UriBuilder;
use Neos\Flow\Persistence\Doctrine\QueryResult;
use Neos\Flow\Security\Context;
use Neos\Neos\Service\UserService;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Sitegeist\GrapeVine\Domain\Model\Notification;
use Sitegeist\GrapeVine\Domain\Repository\MessageRepository;
use Sitegeist\GrapeVine\Domain\Repository\NotificationRepository;

#[Flow\Scope("singleton")]
#[Flow\Aspect]
class BackendRedirectionAspect
{
public function __construct(
private readonly NotificationRepository $notificationRepository,
private readonly Context $securityContext,
private readonly Bootstrap $bootstrap,
private readonly ActionRequestFactory $actionRequestFactory,
private readonly ServerRequestFactoryInterface $serverRequestFactory,
) {
}

/**
* @Flow\Inject
* @var UserService
*/
protected UserService $userService;

#[Flow\Around(pointcutExpression: "method(Neos\Neos\Service\BackendRedirectionService->getAfterLoginRedirectionUri())")]
public function redirectToNewMessagesOnLogin(JoinPointInterface $joinPoint): ?string
{
$account = $this->securityContext->getAccount();
/**
* @var QueryResult $notifications
*/
$notifications = $this->notificationRepository->findByAccount($account);
$latestNotification = $notifications->getFirst();

if ($latestNotification instanceof Notification) {
$handler = $this->bootstrap->getActiveRequestHandler();
if ($handler instanceof HttpRequestHandlerInterface) {
$request = $handler->getHttpRequest();
} else {
$request = $this->serverRequestFactory->createServerRequest("get", "/");
}
$actionRequest = $this->actionRequestFactory->createActionRequest($request);
$uriBuilder = new UriBuilder();
$uriBuilder->setRequest($actionRequest);

$uri = $uriBuilder
->reset()
->setCreateAbsoluteUri(true)
->uriFor(
'index',
[
'module' => 'management/messages',
'moduleArguments' => [
'package' => "Sitegeist.Grapevine",
'controller' => "message",
'action' => 'show',
'format' => 'html',
'message' => $latestNotification->getMessage()
]
],
'Backend\Module',
'Neos.Neos'
);
return $uri;
}
return $joinPoint->getAdviceChain()->proceed($joinPoint);
}
}
4 changes: 1 addition & 3 deletions Classes/Command/MessageCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ protected function __construct(
}

/**
* @phpstan-param string[] $recipient
*
* @param string $title
* @param string $text
* @param string $role
Expand All @@ -56,7 +54,7 @@ public function addCommand(string $title, string $text, string $role = 'Neos.Neo

/**
* @var Account[] $accounts
* @phpstan-ignore method.notFound
* @phpstan-ignore-next-line
*/
$accounts = $this->accountRepository->findByRoleIdentifiers($roleObject->getIdentifier());
foreach ($accounts as $account) {
Expand Down
52 changes: 26 additions & 26 deletions Classes/Controller/MessageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,50 @@ class MessageController extends AbstractModuleController
protected $defaultViewObjectName = FusionView::class;

public function __construct(
private readonly MessageRepository $messageRepository,
private readonly MessageRepository $messageRepository,
private readonly NotificationRepository $notificationRepository,
private readonly Context $securityContext,
private readonly MenuHelper $menuHelper
private readonly Context $securityContext,
) {
}

public function indexAction(): void
{
$account = $this->securityContext->getAccount();
/**
* @var QueryResult $notifications
*/
$notifications = $this->notificationRepository->findByAccount($account);
if ($notifications->count() === 0) {

$uriBuilder = new UriBuilder();
$uriBuilder->setRequest($this->request->getMainRequest());
$uri = $uriBuilder
->reset()
->setCreateAbsoluteUri(true)
->uriFor('index', ['module' => 'content'], 'Backend\Module', 'Neos.Neos');
$this->redirectToUri($uri);
}
$this->view->assign('notifications', $notifications);
}

public function listAction(): void
{
$this->securityContext->getRoles();
$this->view->assign('messages',
$this->messageRepository->findByRoleIdentifiers(
$this->view->assignMultiple([
'messages' => $this->messageRepository->findByRoleIdentifiers(
array_values(
array_map(
fn(Role $role) => $role->getIdentifier(),
$this->securityContext->getRoles()
)
)
),
'notifications' => $this->notificationRepository->findByAccount(
$this->securityContext->getAccount(),
)
);
]);
}

public function showAction(Message $message): void
{
$notification = null;
foreach ($message->getNotifications() as $messageNotification) {
if ($messageNotification->getAccount() === $this->securityContext->getAccount()) {
$notification = $messageNotification;
}
}
$this->view->assign('message', $message);
$this->view->assign('notification', $notification);
}

public function confirmNotificationAction(Notification $notification): void
{
if ($this->securityContext->getAccount() !== $notification->getAccount()) {
throw new \Exception('forbidden access to foreign notifications');
}

$this->notificationRepository->remove($notification);
$this->persistenceManager->persistAll();
$this->forward('index');
}
}
16 changes: 16 additions & 0 deletions Classes/Domain/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,20 @@ public function setAuthor(?Account $author): void
{
$this->author = $author;
}

/**
* @return ArrayCollection<int, Notification>
*/
public function getNotifications()
{
return $this->notifications;
}

/**
* @param ArrayCollection<int, Notification> $notifications
*/
public function setNotifications($notifications): void
{
$this->notifications = $notifications;
}
}
5 changes: 3 additions & 2 deletions Classes/Domain/Repository/MessageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Sitegeist\GrapeVine\Domain\Repository;

use Neos\Flow\Persistence\Doctrine\QueryResult;
use Neos\Flow\Persistence\QueryResultInterface;
use Neos\Flow\Persistence\Repository;
use Neos\Flow\Annotations as Flow;

Expand All @@ -18,9 +19,9 @@ class MessageRepository extends Repository

/**
* @param string[] $roleIdentifiers
* @return QueryResult
* @return QueryResultInterface
*/
public function findByRoleIdentifiers(array $roleIdentifiers): QueryResult
public function findByRoleIdentifiers(array $roleIdentifiers): QueryResultInterface
{
$query = $this->createQuery();
$query = $query->matching(
Expand Down
11 changes: 11 additions & 0 deletions Classes/Domain/Repository/NotificationRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@

namespace Sitegeist\GrapeVine\Domain\Repository;

use Neos\Flow\Persistence\QueryResultInterface;
use Neos\Flow\Persistence\Repository;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Security\Account;
use Sitegeist\GrapeVine\Domain\Model\Message;

#[Flow\Scope('singleton')]
class NotificationRepository extends Repository
{
public function findByAccount(Account $account): QueryResultInterface
{
$query = $this->createQuery();
$query = $query->matching(
$query->equals('account', $account)
);
return $query->execute();
}
}
1 change: 1 addition & 0 deletions Classes/Security/GrapevineSecurityContext.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Sitegeist\GrapeVine\Security;
Expand Down
10 changes: 0 additions & 10 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,3 @@ Neos:
icon: 'icon-bullhorn'
controller: 'Sitegeist\GrapeVine\Controller\MessageController'
privilegeTarget: 'Sitegeist.GrapeVine:MessageModule.Show'
actions:
list:
label: "List all messages"
title: "List all messages"
index:
label: "Login Notifications"
title: "Login Notifications"

# moduleConfiguration:
preferredStartModules: [ 'management/messages', 'content', 'user/usersettings']
73 changes: 35 additions & 38 deletions Resources/Private/Fusion/Root.fusion
Original file line number Diff line number Diff line change
@@ -1,46 +1,11 @@
include: resource://Neos.Fusion/Private/Fusion/Root.fusion

Sitegeist.GrapeVine.MessageController.index = Sitegeist.GrapeVine:LoginNotification
Sitegeist.GrapeVine.MessageController.list = Sitegeist.GrapeVine:MessageList
Sitegeist.GrapeVine.MessageController.index = Sitegeist.GrapeVine:MessageList
Sitegeist.GrapeVine.MessageController.show = Sitegeist.GrapeVine:MessageShow

prototype(Sitegeist.GrapeVine:LoginNotification) < prototype(Neos.Fusion:Component) {
notifications = ${notifications}

renderer = afx`
<h1>LOGIN NOTIFICATIONS</h1>
<table class="neos-table">
<thead>
<tr>
<td>Title</td>
<td>Message</td>
<td>Recipient roles</td>
<td></td>
</tr>
</thead>
<tbody>
<Neos.Fusion:Loop items={props.notifications} itemName="notification">
<tr>
<td>{notification.message.title}</td>
<td>{notification.message.text}</td>
<td>{notification.message.recipientRoleIdentifier}</td>
<td>
<Neos.Fusion:Link.Action
href.action="show"
href.arguments.message={notification.message}
>
Show
</Neos.Fusion:Link.Action>
</td>
</tr>
</Neos.Fusion:Loop>
</tbody>
</table>
`
}

prototype(Sitegeist.GrapeVine:MessageList) < prototype(Neos.Fusion:Component) {
messages = ${messages}
notifications = ${notifications}

renderer = afx`
<table class="neos-table">
Expand All @@ -55,16 +20,32 @@ prototype(Sitegeist.GrapeVine:MessageList) < prototype(Neos.Fusion:Component) {
<tbody>
<Neos.Fusion:Loop items={props.messages} itemName="message">
<tr>
<td>{message.title}</td>
<td>
<Neos.Fusion:Loop items={props.notifications} itemName="notification">
{notification.message == message ? '** NEW ** ' : ''}
</Neos.Fusion:Loop>
{message.title}
</td>
<td>{message.text}</td>
<td>{message.recipientRoleIdentifier}</td>
<td>
<Neos.Fusion:Link.Action
class="neos-button"
href.action="show"
href.arguments.message={message}
>
Show
</Neos.Fusion:Link.Action>
<Neos.Fusion:Loop items={props.notifications} itemName="notification">
<Neos.Fusion:Link.Action
@if={notification.message == message}
class="neos-button"
href.action="confirmNotification"
href.arguments.notification={notification}
>
Confirm
</Neos.Fusion:Link.Action>
</Neos.Fusion:Loop>
</td>
</tr>
</Neos.Fusion:Loop>
Expand All @@ -80,5 +61,21 @@ prototype(Sitegeist.GrapeVine:MessageShow) < prototype(Neos.Fusion:Component) {
<h1>{props.message.title}</h1>
<pre>{props.message.text}</pre>
<pre>{props.message.recipeintRoleIdentifier}</pre>

<Neos.Fusion:Link.Action
class="neos-button"
href.action="index"
>
Back
</Neos.Fusion:Link.Action>

<Neos.Fusion:Link.Action
@if={notification}
class="neos-button"
href.action="confirmNotification"
href.arguments.notification={notification}
>
Confirm Notification
</Neos.Fusion:Link.Action>
`
}

0 comments on commit 67f4d37

Please sign in to comment.