Skip to content

Commit fb94c3b

Browse files
committed
Implement a command to dismiss a notice.
Implement and use an API endpoint to dismiss a notice.
1 parent 84269cd commit fb94c3b

File tree

9 files changed

+193
-56
lines changed

9 files changed

+193
-56
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Dismiss a notice.
3+
*
4+
* @author Olaf Braun
5+
* @copyright 2001-2025 WoltLab GmbH
6+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7+
* @since 6.3
8+
* @woltlabExcludeBundle tiny
9+
*/
10+
11+
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
12+
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
13+
14+
export async function dismissNotice(noticeId: number): Promise<ApiResult<[]>> {
15+
try {
16+
await prepareRequest(`${window.WSC_RPC_API_URL}core/notices/${noticeId}/dismiss`).post().fetchAsJson();
17+
} catch (e) {
18+
return apiResultFromError(e);
19+
}
20+
21+
return apiResultFromValue([]);
22+
}

ts/WoltLabSuite/Core/Controller/Notice/Dismiss.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,26 @@
77
* @woltlabExcludeBundle tiny
88
*/
99

10-
import * as Ajax from "../../Ajax";
10+
import { dismissNotice } from "WoltLabSuite/Core/Api/Notices/DismissNotice";
11+
import { promiseMutex } from "WoltLabSuite/Core/Helper/PromiseMutex";
1112

1213
/**
1314
* Initializes dismiss buttons.
1415
*/
1516
export function setup(): void {
16-
document.querySelectorAll(".jsDismissNoticeButton").forEach((button) => {
17-
button.addEventListener("click", (ev) => click(ev));
17+
document.querySelectorAll<HTMLElement>(".jsDismissNoticeButton").forEach((button) => {
18+
button.addEventListener(
19+
"click",
20+
promiseMutex(() => click(button)),
21+
);
1822
});
1923
}
2024

2125
/**
2226
* Sends a request to dismiss a notice and removes it afterwards.
2327
*/
24-
function click(event: Event): void {
25-
const button = event.currentTarget as HTMLElement;
28+
async function click(button: HTMLElement): Promise<void> {
29+
await dismissNotice(parseInt(button.dataset.objectId!, 10));
2630

27-
Ajax.apiOnce({
28-
data: {
29-
actionName: "dismiss",
30-
className: "wcf\\data\\notice\\NoticeAction",
31-
objectIDs: [button.dataset.objectId!],
32-
},
33-
success: () => {
34-
button.parentElement!.remove();
35-
},
36-
});
31+
button.parentElement!.remove();
3732
}

wcfsetup/install/files/js/WoltLabSuite/Core/Api/Notices/DismissNotice.js

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Notice/Dismiss.js

Lines changed: 5 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static function (\wcf\event\endpoint\ControllerCollecting $event) {
241241
$event->register(new \wcf\system\endpoint\controller\core\notices\DeleteNotice());
242242
$event->register(new \wcf\system\endpoint\controller\core\notices\GetShowOrder());
243243
$event->register(new \wcf\system\endpoint\controller\core\notices\ChangeShowOrder());
244+
$event->register(new \wcf\system\endpoint\controller\core\notices\DismissNotice());
244245
$event->register(new \wcf\system\endpoint\controller\core\reactions\types\EnableType());
245246
$event->register(new \wcf\system\endpoint\controller\core\reactions\types\DisableType());
246247
$event->register(new \wcf\system\endpoint\controller\core\reactions\types\DeleteType());
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace wcf\command\notice;
4+
5+
use wcf\data\notice\Notice;
6+
use wcf\event\notice\NoticeDismissed;
7+
use wcf\system\event\EventHandler;
8+
use wcf\system\user\storage\UserStorageHandler;
9+
use wcf\system\WCF;
10+
11+
/**
12+
* Dismisses a notice for the current user.
13+
*
14+
* @author Olaf Braun
15+
* @copyright 2001-2025 WoltLab GmbH
16+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
17+
* @since 6.3
18+
*/
19+
final class DismissNotice
20+
{
21+
public function __construct(
22+
private readonly Notice $notice,
23+
) {}
24+
25+
public function __invoke(): void
26+
{
27+
if (!$this->notice->isDismissible) {
28+
return;
29+
}
30+
31+
if (WCF::getUser()->userID) {
32+
$this->dismissForUser($this->notice, WCF::getUser()->userID);
33+
} else {
34+
$this->dismissForGuest($this->notice);
35+
}
36+
37+
$event = new NoticeDismissed($this->notice);
38+
EventHandler::getInstance()->fire($event);
39+
}
40+
41+
private function dismissForUser(Notice $notice, int $userID): void
42+
{
43+
$sql = "INSERT IGNORE INTO wcf1_notice_dismissed
44+
(noticeID, userID)
45+
VALUES (?, ?)";
46+
$statement = WCF::getDB()->prepare($sql);
47+
$statement->execute([
48+
$notice->noticeID,
49+
$userID,
50+
]);
51+
52+
UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'dismissedNotices');
53+
}
54+
55+
private function dismissForGuest(Notice $notice): void
56+
{
57+
$sessionVar = WCF::getSession()->getVar('dismissedNotices') ?? '';
58+
$dismissedNotices = @\unserialize($sessionVar) ?: [];
59+
$dismissedNotices[] = $notice->noticeID;
60+
61+
WCF::getSession()->register('dismissedNotices', \serialize($dismissedNotices));
62+
}
63+
}

wcfsetup/install/files/lib/data/notice/NoticeAction.class.php

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
namespace wcf\data\notice;
44

5+
use wcf\command\notice\DismissNotice;
56
use wcf\data\AbstractDatabaseObjectAction;
67
use wcf\data\IToggleAction;
78
use wcf\data\TDatabaseObjectToggle;
89
use wcf\system\condition\ConditionHandler;
9-
use wcf\system\user\storage\UserStorageHandler;
10-
use wcf\system\WCF;
1110

1211
/**
1312
* Executes notice-related actions.
@@ -76,33 +75,14 @@ public function delete()
7675
* Dismisses a certain notice.
7776
*
7877
* @return int[]
78+
*
79+
* @deprecated 6.3 Use the `DismissNotice` command instead.
7980
*/
8081
public function dismiss()
8182
{
82-
if (WCF::getUser()->userID) {
83-
$sql = "INSERT IGNORE INTO wcf1_notice_dismissed
84-
(noticeID, userID)
85-
VALUES (?, ?)";
86-
$statement = WCF::getDB()->prepare($sql);
87-
$statement->execute([
88-
\reset($this->objectIDs),
89-
WCF::getUser()->userID,
90-
]);
91-
92-
UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'dismissedNotices');
93-
} else {
94-
$dismissedNotices = WCF::getSession()->getVar('dismissedNotices');
95-
if ($dismissedNotices !== null) {
96-
$dismissedNotices = @\unserialize($dismissedNotices);
97-
$dismissedNotices[] = \reset($this->objectIDs);
98-
} else {
99-
$dismissedNotices = [
100-
\reset($this->objectIDs),
101-
];
102-
}
103-
104-
WCF::getSession()->register('dismissedNotices', \serialize($dismissedNotices));
105-
}
83+
$editor = $this->getSingleObject();
84+
85+
(new DismissNotice($editor->getDecoratedObject()))();
10686

10787
return [
10888
'noticeID' => \reset($this->objectIDs),
@@ -113,6 +93,8 @@ public function dismiss()
11393
* Validates the 'dismiss' action.
11494
*
11595
* @return void
96+
*
97+
* @deprecated 6.3
11698
*/
11799
public function validateDismiss()
118100
{
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace wcf\event\notice;
4+
5+
use wcf\data\notice\Notice;
6+
use wcf\event\IPsr14Event;
7+
8+
/**
9+
* Indicates that a notice has been dismissed by the current user.
10+
*
11+
* @author Olaf Braun
12+
* @copyright 2001-2025 WoltLab GmbH
13+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14+
* @since 6.3
15+
*/
16+
final class NoticeDismissed implements IPsr14Event
17+
{
18+
public function __construct(public readonly Notice $notice) {}
19+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace wcf\system\endpoint\controller\core\notices;
4+
5+
use Laminas\Diactoros\Response\JsonResponse;
6+
use Psr\Http\Message\ResponseInterface;
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use wcf\data\notice\Notice;
9+
use wcf\http\Helper;
10+
use wcf\system\endpoint\IController;
11+
use wcf\system\endpoint\PostRequest;
12+
use wcf\system\exception\PermissionDeniedException;
13+
14+
/**
15+
* API endpoint to dismiss a notice for the current user.
16+
*
17+
* @author Olaf Braun
18+
* @copyright 2001-2025 WoltLab GmbH
19+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
20+
* @since 6.3
21+
*/
22+
#[PostRequest('/core/notices/{id:\d+}/dismiss')]
23+
final class DismissNotice implements IController
24+
{
25+
public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
26+
{
27+
$notice = Helper::fetchObjectFromRequestParameter($variables['id'], Notice::class);
28+
29+
$this->assertNoticeCanBeDismissed($notice);
30+
31+
(new \wcf\command\notice\DismissNotice($notice))();
32+
33+
return new JsonResponse([]);
34+
}
35+
36+
private function assertNoticeCanBeDismissed(Notice $notice): void
37+
{
38+
if (!$notice->isDismissible) {
39+
throw new PermissionDeniedException();
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)