mirror of
https://github.com/flarum/framework.git
synced 2025-03-31 12:47:49 +08:00
feat: Delete all notifications (#3529)
* Add delete all notifications option * chore: `DELETE /api/notifications` as per conventions * test: can delete all notifications Co-authored-by: Sami Mazouz <ilyasmazouz@gmail.com>
This commit is contained in:
parent
b28606b8ef
commit
d02bf0faa1
@ -6,6 +6,7 @@ import Link from '../../common/components/Link';
|
||||
import LoadingIndicator from '../../common/components/LoadingIndicator';
|
||||
import Discussion from '../../common/models/Discussion';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
import Tooltip from '../../common/components/Tooltip';
|
||||
|
||||
/**
|
||||
* The `NotificationList` component displays a list of the logged-in user's
|
||||
@ -34,15 +35,36 @@ export default class NotificationList extends Component {
|
||||
|
||||
items.add(
|
||||
'mark_all_as_read',
|
||||
<Button
|
||||
className="Button Button--link"
|
||||
icon="fas fa-check"
|
||||
title={app.translator.trans('core.forum.notifications.mark_all_as_read_tooltip')}
|
||||
onclick={state.markAllAsRead.bind(state)}
|
||||
/>,
|
||||
<Tooltip text={app.translator.trans('core.forum.notifications.mark_all_as_read_tooltip')}>
|
||||
<Button
|
||||
className="Button Button--link"
|
||||
data-container=".NotificationList"
|
||||
icon="fas fa-check"
|
||||
title={app.translator.trans('core.forum.notifications.mark_all_as_read_tooltip')}
|
||||
onclick={state.markAllAsRead.bind(state)}
|
||||
/>
|
||||
</Tooltip>,
|
||||
70
|
||||
);
|
||||
|
||||
items.add(
|
||||
'delete_all',
|
||||
<Tooltip text={app.translator.trans('core.forum.notifications.delete_all_tooltip')}>
|
||||
<Button
|
||||
className="Button Button--link"
|
||||
data-container=".NotificationList"
|
||||
icon="fas fa-trash-alt"
|
||||
title={app.translator.trans('core.forum.notifications.delete_all_tooltip')}
|
||||
onclick={() => {
|
||||
if (confirm(app.translator.trans('core.forum.notifications.delete_all_confirm'))) {
|
||||
state.deleteAll.call(state);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Tooltip>,
|
||||
50
|
||||
);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
@ -46,4 +46,20 @@ export default class NotificationListState extends PaginatedListState<Notificati
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all of the notifications for this user.
|
||||
*/
|
||||
deleteAll() {
|
||||
if (this.pages.length === 0) return;
|
||||
|
||||
app.session.user?.pushAttributes({ unreadNotificationCount: 0 });
|
||||
|
||||
this.pages = [];
|
||||
|
||||
return app.request({
|
||||
url: app.forum.attribute('apiUrl') + '/notifications',
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
.NotificationList {
|
||||
overflow: hidden;
|
||||
|
||||
.App-primaryControl > button:not(:last-of-type) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
@media @tablet-up {
|
||||
padding: 12px 15px;
|
||||
|
@ -394,6 +394,8 @@ core:
|
||||
|
||||
# These translations are used by the Notifications dropdown, a.k.a. "the bell".
|
||||
notifications:
|
||||
delete_all_confirm: Are you sure you want to delete all notifications? This action is not reversable
|
||||
delete_all_tooltip: Delete all notifications
|
||||
discussion_renamed_text: "{username} changed the title"
|
||||
empty_text: No Notifications
|
||||
mark_all_as_read_tooltip: => core.ref.mark_all_as_read
|
||||
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Api\Controller;
|
||||
|
||||
use Flarum\Http\RequestUtil;
|
||||
use Flarum\Notification\Command\DeleteAllNotifications;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class DeleteAllNotificationsController extends AbstractDeleteController
|
||||
{
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $bus;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $bus
|
||||
*/
|
||||
public function __construct(Dispatcher $bus)
|
||||
{
|
||||
$this->bus = $bus;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function delete(ServerRequestInterface $request)
|
||||
{
|
||||
$this->bus->dispatch(
|
||||
new DeleteAllNotifications(RequestUtil::getActor($request))
|
||||
);
|
||||
}
|
||||
}
|
@ -122,6 +122,13 @@ return function (RouteCollection $map, RouteHandlerFactory $route) {
|
||||
$route->toController(Controller\UpdateNotificationController::class)
|
||||
);
|
||||
|
||||
// Delete all notifications for the current user.
|
||||
$map->delete(
|
||||
'/notifications',
|
||||
'notifications.deleteAll',
|
||||
$route->toController(Controller\DeleteAllNotificationsController::class)
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Discussions
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Notification\Command;
|
||||
|
||||
use Flarum\User\User;
|
||||
|
||||
class DeleteAllNotifications
|
||||
{
|
||||
/**
|
||||
* The user performing the action.
|
||||
*
|
||||
* @var User
|
||||
*/
|
||||
public $actor;
|
||||
|
||||
/**
|
||||
* @param User $actor The user performing the action.
|
||||
*/
|
||||
public function __construct(User $actor)
|
||||
{
|
||||
$this->actor = $actor;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Notification\Command;
|
||||
|
||||
use Flarum\Notification\Event\DeletedAll;
|
||||
use Flarum\Notification\NotificationRepository;
|
||||
use Flarum\User\Exception\NotAuthenticatedException;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class DeleteAllNotificationsHandler
|
||||
{
|
||||
/**
|
||||
* @var NotificationRepository
|
||||
*/
|
||||
protected $notifications;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* @param NotificationRepository $notifications
|
||||
* @param Dispatcher $events
|
||||
*/
|
||||
public function __construct(NotificationRepository $notifications, Dispatcher $events)
|
||||
{
|
||||
$this->notifications = $notifications;
|
||||
$this->events = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteAllNotifications $command
|
||||
* @throws NotAuthenticatedException
|
||||
*/
|
||||
public function handle(DeleteAllNotifications $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$actor->assertRegistered();
|
||||
|
||||
$this->notifications->deleteAll($actor);
|
||||
|
||||
$this->events->dispatch(new DeletedAll($actor, Carbon::now()));
|
||||
}
|
||||
}
|
32
framework/core/src/Notification/Event/DeletedAll.php
Normal file
32
framework/core/src/Notification/Event/DeletedAll.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Notification\Event;
|
||||
|
||||
use DateTime;
|
||||
use Flarum\User\User;
|
||||
|
||||
class DeletedAll
|
||||
{
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
public $actor;
|
||||
|
||||
/**
|
||||
* @var DateTime
|
||||
*/
|
||||
public $timestamp;
|
||||
|
||||
public function __construct(User $user, DateTime $timestamp)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
}
|
@ -54,4 +54,9 @@ class NotificationRepository
|
||||
->whereNull('read_at')
|
||||
->update(['read_at' => Carbon::now()]);
|
||||
}
|
||||
|
||||
public function deleteAll(User $user)
|
||||
{
|
||||
Notification::where('user_id', $user->id)->delete();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Tests\integration\api\notifications;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Testing\integration\TestCase;
|
||||
use Flarum\User\User;
|
||||
|
||||
class DeleteTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->prepareDatabase([
|
||||
'users' => [
|
||||
$this->normalUser(),
|
||||
],
|
||||
'discussions' => [
|
||||
['id' => 1, 'title' => 'Test Discussion', 'user_id' => 2, 'comment_count' => 1],
|
||||
['id' => 2, 'title' => 'Test Discussion', 'user_id' => 2, 'comment_count' => 1],
|
||||
['id' => 3, 'title' => 'Test Discussion', 'user_id' => 1, 'comment_count' => 1],
|
||||
['id' => 4, 'title' => 'Test Discussion', 'user_id' => 1, 'comment_count' => 1],
|
||||
],
|
||||
'notifications' => [
|
||||
['id' => 1, 'user_id' => 1, 'type' => 'discussionRenamed', 'subject_id' => 1, 'from_user_id' => 2, 'read_at' => Carbon::now()],
|
||||
['id' => 2, 'user_id' => 1, 'type' => 'discussionRenamed', 'subject_id' => 2, 'from_user_id' => 2, 'read_at' => null],
|
||||
['id' => 3, 'user_id' => 2, 'type' => 'discussionRenamed', 'subject_id' => 3, 'from_user_id' => 1, 'read_at' => Carbon::now()],
|
||||
['id' => 4, 'user_id' => 2, 'type' => 'discussionRenamed', 'subject_id' => 4, 'from_user_id' => 1, 'read_at' => null],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider canDeleteAllNotifications
|
||||
* @test
|
||||
*/
|
||||
public function user_can_delete_all_notifications(int $authenticatedAs)
|
||||
{
|
||||
$this->app();
|
||||
|
||||
$this->assertEquals(2, User::query()->find($authenticatedAs)->notifications()->count());
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('DELETE', '/api/notifications', compact('authenticatedAs')),
|
||||
);
|
||||
|
||||
$this->assertEquals(204, $response->getStatusCode());
|
||||
$this->assertEquals(0, User::query()->find($authenticatedAs)->notifications()->count());
|
||||
}
|
||||
|
||||
public function canDeleteAllNotifications(): array
|
||||
{
|
||||
return [
|
||||
[1],
|
||||
[2]
|
||||
];
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user