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: 0 additions & 6 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -24882,12 +24882,6 @@ parameters:
count: 1
path: src/lib/Repository/NameSchema/NameSchemaService.php

-
message: '#^Parameter \#1 \$module of class Ibexa\\Core\\Base\\Exceptions\\UnauthorizedException constructor expects string, int\<min, \-1\>\|int\<1, max\> given\.$#'
identifier: argument.type
count: 1
path: src/lib/Repository/NotificationService.php

-
message: '#^Parameter \#2 \$whatIsWrong of class Ibexa\\Core\\Base\\Exceptions\\InvalidArgumentException constructor expects string, int given\.$#'
identifier: argument.type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public function markNotificationAsRead(Notification $notification): void
$this->innerService->markNotificationAsRead($notification);
}

public function markNotificationAsUnread(Notification $notification): void
{
$this->innerService->markNotificationAsUnread($notification);
}

public function getPendingNotificationCount(): int
{
return $this->innerService->getPendingNotificationCount();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Core\Repository\Events\Notification;

use Ibexa\Contracts\Core\Repository\Event\BeforeEvent;
use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;

final class BeforeMarkNotificationAsUnreadEvent extends BeforeEvent
{
private Notification $notification;

public function __construct(Notification $notification)
{
$this->notification = $notification;
}

public function getNotification(): Notification
{
return $this->notification;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Core\Repository\Events\Notification;

use Ibexa\Contracts\Core\Repository\Event\AfterEvent;
use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;

final class MarkNotificationAsUnreadEvent extends AfterEvent
{
private Notification $notification;

public function __construct(Notification $notification)
{
$this->notification = $notification;
}

public function getNotification(): Notification
{
return $this->notification;
}
}
8 changes: 8 additions & 0 deletions src/contracts/Repository/NotificationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ public function getNotification(int $notificationId): Notification;
*/
public function markNotificationAsRead(Notification $notification): void;

/**
* Marks the given notification as unread so it is shown again as new to the user.
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException
*/
public function markNotificationAsUnread(Notification $notification): void;

/**
* Get count of unread users notifications.
*
Expand Down
20 changes: 20 additions & 0 deletions src/lib/Event/NotificationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeCreateNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeDeleteNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeMarkNotificationAsReadEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeMarkNotificationAsUnreadEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\CreateNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\DeleteNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\MarkNotificationAsReadEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\MarkNotificationAsUnreadEvent;
use Ibexa\Contracts\Core\Repository\NotificationService as NotificationServiceInterface;
use Ibexa\Contracts\Core\Repository\Values\Notification\CreateStruct;
use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
Expand Down Expand Up @@ -52,6 +54,24 @@ public function markNotificationAsRead(Notification $notification): void
);
}

public function markNotificationAsUnread(Notification $notification): void
{
$eventData = [$notification];

$beforeEvent = new BeforeMarkNotificationAsUnreadEvent(...$eventData);

$this->eventDispatcher->dispatch($beforeEvent);
if ($beforeEvent->isPropagationStopped()) {
return;
}

$this->innerService->markNotificationAsUnread($notification);

$this->eventDispatcher->dispatch(
new MarkNotificationAsUnreadEvent(...$eventData)
);
}

public function createNotification(CreateStruct $createStruct): Notification
{
$eventData = [$createStruct];
Expand Down
24 changes: 23 additions & 1 deletion src/lib/Repository/NotificationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public function markNotificationAsRead(APINotification $notification): void
}

if ($notification->ownerId !== $currentUserId) {
throw new UnauthorizedException($notification->id, 'Notification');
throw new UnauthorizedException('notification', 'update', ['id' => $notification->id]);
}

if (!$notification->isPending) {
Expand All @@ -125,6 +125,28 @@ public function markNotificationAsRead(APINotification $notification): void
$this->persistenceHandler->updateNotification($notification, $updateStruct);
}

public function markNotificationAsUnread(APINotification $notification): void
{
$currentUserId = $this->getCurrentUserId();

if (!$notification->id) {
throw new NotFoundException('Notification', $notification->id);
}

if ($notification->ownerId !== $currentUserId) {
throw new UnauthorizedException('notification', 'update', ['id' => $notification->id]);
}

if ($notification->isPending) {
return;
}

$updateStruct = new UpdateStruct();
$updateStruct->isPending = true;

$this->persistenceHandler->updateNotification($notification, $updateStruct);
}

/**
* {@inheritdoc}
*/
Expand Down
5 changes: 5 additions & 0 deletions src/lib/Repository/SiteAccessAware/NotificationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ public function markNotificationAsRead(Notification $notification): void
$this->service->markNotificationAsRead($notification);
}

public function markNotificationAsUnread(Notification $notification): void
{
$this->service->markNotificationAsUnread($notification);
}

/**
* Get count of unread users notifications.
*
Expand Down
22 changes: 22 additions & 0 deletions tests/integration/Core/Repository/NotificationServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ public function testMarkNotificationAsRead()
$this->assertFalse($notification->isPending);
}

/**
* @covers \Ibexa\Contracts\Core\Repository\NotificationService::markNotificationAsUnread()
*/
public function testMarkNotificationAsUnread(): void
{
$repository = $this->getRepository();

$notificationId = $this->generateId('notification', 5);
$notificationService = $repository->getNotificationService();

$notification = $notificationService->getNotification($notificationId);
$notificationService->markNotificationAsRead($notification);

$notification = $notificationService->getNotification($notificationId);
self::assertFalse($notification->isPending);

$notificationService->markNotificationAsUnread($notification);
$notification = $notificationService->getNotification($notificationId);

self::assertTrue($notification->isPending);
}

/**
* @covers \Ibexa\Contracts\Core\Repository\NotificationService::getPendingNotificationCount()
*/
Expand Down
105 changes: 92 additions & 13 deletions tests/lib/Event/NotificationServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeCreateNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeDeleteNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeMarkNotificationAsReadEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\BeforeMarkNotificationAsUnreadEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\CreateNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\DeleteNotificationEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\MarkNotificationAsReadEvent;
use Ibexa\Contracts\Core\Repository\Events\Notification\MarkNotificationAsUnreadEvent;
use Ibexa\Contracts\Core\Repository\NotificationService as NotificationServiceInterface;
use Ibexa\Contracts\Core\Repository\Values\Notification\CreateStruct;
use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
Expand Down Expand Up @@ -63,9 +65,13 @@ public function testReturnCreateNotificationResultInBeforeEvents()
$innerServiceMock = $this->createMock(NotificationServiceInterface::class);
$innerServiceMock->method('createNotification')->willReturn($notification);

$traceableEventDispatcher->addListener(BeforeCreateNotificationEvent::class, static function (BeforeCreateNotificationEvent $event) use ($eventNotification) {
$event->setNotification($eventNotification);
}, 10);
$traceableEventDispatcher->addListener(
BeforeCreateNotificationEvent::class,
static function (BeforeCreateNotificationEvent $event) use ($eventNotification): void {
$event->setNotification($eventNotification);
},
10
);

$service = new NotificationService($innerServiceMock, $traceableEventDispatcher);
$result = $service->createNotification(...$parameters);
Expand Down Expand Up @@ -97,10 +103,14 @@ public function testCreateNotificationStopPropagationInBeforeEvents()
$innerServiceMock = $this->createMock(NotificationServiceInterface::class);
$innerServiceMock->method('createNotification')->willReturn($notification);

$traceableEventDispatcher->addListener(BeforeCreateNotificationEvent::class, static function (BeforeCreateNotificationEvent $event) use ($eventNotification) {
$event->setNotification($eventNotification);
$event->stopPropagation();
}, 10);
$traceableEventDispatcher->addListener(
BeforeCreateNotificationEvent::class,
static function (BeforeCreateNotificationEvent $event) use ($eventNotification): void {
$event->setNotification($eventNotification);
$event->stopPropagation();
},
10
);

$service = new NotificationService($innerServiceMock, $traceableEventDispatcher);
$result = $service->createNotification(...$parameters);
Expand Down Expand Up @@ -156,9 +166,13 @@ public function testDeleteNotificationStopPropagationInBeforeEvents()

$innerServiceMock = $this->createMock(NotificationServiceInterface::class);

$traceableEventDispatcher->addListener(BeforeDeleteNotificationEvent::class, static function (BeforeDeleteNotificationEvent $event) {
$event->stopPropagation();
}, 10);
$traceableEventDispatcher->addListener(
BeforeDeleteNotificationEvent::class,
static function (BeforeDeleteNotificationEvent $event): void {
$event->stopPropagation();
},
10
);

$service = new NotificationService($innerServiceMock, $traceableEventDispatcher);
$service->deleteNotification(...$parameters);
Expand Down Expand Up @@ -200,6 +214,31 @@ public function testMarkNotificationAsReadEvents()
$this->assertSame([], $traceableEventDispatcher->getNotCalledListeners());
}

public function testMarkNotificationAsUnreadEvents(): void
{
$traceableEventDispatcher = $this->getEventDispatcher(
BeforeMarkNotificationAsUnreadEvent::class,
MarkNotificationAsUnreadEvent::class
);

$parameters = [
$this->createMock(Notification::class),
];

$innerServiceMock = $this->createMock(NotificationServiceInterface::class);

$service = new NotificationService($innerServiceMock, $traceableEventDispatcher);
$service->markNotificationAsUnread(...$parameters);

$calledListeners = $this->getListenersStack($traceableEventDispatcher->getCalledListeners());

self::assertSame($calledListeners, [
[BeforeMarkNotificationAsUnreadEvent::class, 0],
[MarkNotificationAsUnreadEvent::class, 0],
]);
self::assertSame([], $traceableEventDispatcher->getNotCalledListeners());
}

public function testMarkNotificationAsReadStopPropagationInBeforeEvents()
{
$traceableEventDispatcher = $this->getEventDispatcher(
Expand All @@ -213,9 +252,13 @@ public function testMarkNotificationAsReadStopPropagationInBeforeEvents()

$innerServiceMock = $this->createMock(NotificationServiceInterface::class);

$traceableEventDispatcher->addListener(BeforeMarkNotificationAsReadEvent::class, static function (BeforeMarkNotificationAsReadEvent $event) {
$event->stopPropagation();
}, 10);
$traceableEventDispatcher->addListener(
BeforeMarkNotificationAsReadEvent::class,
static function (BeforeMarkNotificationAsReadEvent $event): void {
$event->stopPropagation();
},
10
);

$service = new NotificationService($innerServiceMock, $traceableEventDispatcher);
$service->markNotificationAsRead(...$parameters);
Expand All @@ -231,6 +274,42 @@ public function testMarkNotificationAsReadStopPropagationInBeforeEvents()
[MarkNotificationAsReadEvent::class, 0],
]);
}

public function testMarkNotificationAsUnreadStopPropagationInBeforeEvents(): void
{
$traceableEventDispatcher = $this->getEventDispatcher(
BeforeMarkNotificationAsUnreadEvent::class,
MarkNotificationAsUnreadEvent::class
);

$parameters = [
$this->createMock(Notification::class),
];

$innerServiceMock = $this->createMock(NotificationServiceInterface::class);

$traceableEventDispatcher->addListener(
BeforeMarkNotificationAsUnreadEvent::class,
static function (BeforeMarkNotificationAsUnreadEvent $event): void {
$event->stopPropagation();
},
10
);

$service = new NotificationService($innerServiceMock, $traceableEventDispatcher);
$service->markNotificationAsUnread(...$parameters);

$calledListeners = $this->getListenersStack($traceableEventDispatcher->getCalledListeners());
$notCalledListeners = $this->getListenersStack($traceableEventDispatcher->getNotCalledListeners());

self::assertSame($calledListeners, [
[BeforeMarkNotificationAsUnreadEvent::class, 10],
]);
self::assertSame($notCalledListeners, [
[BeforeMarkNotificationAsUnreadEvent::class, 0],
[MarkNotificationAsUnreadEvent::class, 0],
]);
}
}

class_alias(NotificationServiceTest::class, 'eZ\Publish\Core\Event\Tests\NotificationServiceTest');
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ public function testMarkNotificationAsReadDecorator()
$decoratedService->markNotificationAsRead(...$parameters);
}

public function testMarkNotificationAsUnreadDecorator(): void
{
$serviceMock = $this->createServiceMock();
$decoratedService = $this->createDecorator($serviceMock);

$parameters = [$this->createMock(Notification::class)];

$serviceMock->expects(self::once())->method('markNotificationAsUnread')->with(...$parameters);

$decoratedService->markNotificationAsUnread(...$parameters);
}

public function testGetPendingNotificationCountDecorator()
{
$serviceMock = $this->createServiceMock();
Expand Down
Loading