Skip to content

Commit 03ed815

Browse files
Cyperghostdtdesign
andauthored
Implement a command to dismiss a notice (#6427)
* Implement a command to dismiss a notice. Implement and use an API endpoint to dismiss a notice. * Check if the notice can be dismissed not in the command * Minor fixes --------- Co-authored-by: Alexander Ebert <ebert@woltlab.com>
1 parent 812f218 commit 03ed815

9 files changed

Lines changed: 187 additions & 56 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
*/
9+
10+
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
11+
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
12+
13+
export async function dismissNotice(noticeId: number): Promise<ApiResult<[]>> {
14+
try {
15+
await prepareRequest(`${window.WSC_RPC_API_URL}core/notices/${noticeId}/dismiss`).post().fetchAsJson();
16+
} catch (e) {
17+
return apiResultFromError(e);
18+
}
19+
20+
return apiResultFromValue([]);
21+
}

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

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,28 @@
44
* @author Alexander Ebert
55
* @copyright 2001-2019 WoltLab GmbH
66
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7-
* @woltlabExcludeBundle tiny
87
*/
98

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

1212
/**
1313
* Initializes dismiss buttons.
1414
*/
1515
export function setup(): void {
16-
document.querySelectorAll(".jsDismissNoticeButton").forEach((button) => {
17-
button.addEventListener("click", (ev) => click(ev));
16+
document.querySelectorAll<HTMLElement>(".jsDismissNoticeButton").forEach((button) => {
17+
button.addEventListener(
18+
"click",
19+
promiseMutex(() => click(button)),
20+
);
1821
});
1922
}
2023

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

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-
});
30+
button.parentElement!.remove();
3731
}

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

Lines changed: 22 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 & 16 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: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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.
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 (WCF::getUser()->userID) {
28+
$this->dismissForUser($this->notice, WCF::getUser()->userID);
29+
} else {
30+
$this->dismissForGuest($this->notice);
31+
}
32+
33+
$event = new NoticeDismissed($this->notice);
34+
EventHandler::getInstance()->fire($event);
35+
}
36+
37+
private function dismissForUser(Notice $notice, int $userID): void
38+
{
39+
$sql = "INSERT IGNORE INTO wcf1_notice_dismissed
40+
(noticeID, userID)
41+
VALUES (?, ?)";
42+
$statement = WCF::getDB()->prepare($sql);
43+
$statement->execute([
44+
$notice->noticeID,
45+
$userID,
46+
]);
47+
48+
UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'dismissedNotices');
49+
}
50+
51+
private function dismissForGuest(Notice $notice): void
52+
{
53+
$sessionVar = WCF::getSession()->getVar('dismissedNotices') ?? '';
54+
$dismissedNotices = @\unserialize($sessionVar) ?: [];
55+
$dismissedNotices[] = $notice->noticeID;
56+
57+
WCF::getSession()->register('dismissedNotices', \serialize($dismissedNotices));
58+
}
59+
}

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

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44

55
use wcf\command\notice\DisableNotice;
66
use wcf\command\notice\EnableNotice;
7+
use wcf\command\notice\DismissNotice;
78
use wcf\data\AbstractDatabaseObjectAction;
89
use wcf\data\IToggleAction;
910
use wcf\system\condition\ConditionHandler;
10-
use wcf\system\user\storage\UserStorageHandler;
11-
use wcf\system\WCF;
1211

1312
/**
1413
* Executes notice-related actions.
@@ -75,32 +74,14 @@ public function delete()
7574
* Dismisses a certain notice.
7675
*
7776
* @return int[]
77+
* @deprecated 6.3 Use the `DismissNotice` command instead.
7878
*/
7979
public function dismiss()
8080
{
81-
if (WCF::getUser()->userID) {
82-
$sql = "INSERT IGNORE INTO wcf1_notice_dismissed
83-
(noticeID, userID)
84-
VALUES (?, ?)";
85-
$statement = WCF::getDB()->prepare($sql);
86-
$statement->execute([
87-
\reset($this->objectIDs),
88-
WCF::getUser()->userID,
89-
]);
90-
91-
UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'dismissedNotices');
92-
} else {
93-
$dismissedNotices = WCF::getSession()->getVar('dismissedNotices');
94-
if ($dismissedNotices !== null) {
95-
$dismissedNotices = @\unserialize($dismissedNotices);
96-
$dismissedNotices[] = \reset($this->objectIDs);
97-
} else {
98-
$dismissedNotices = [
99-
\reset($this->objectIDs),
100-
];
101-
}
81+
$editor = $this->getSingleObject();
10282

103-
WCF::getSession()->register('dismissedNotices', \serialize($dismissedNotices));
83+
if ($editor->isDismissible) {
84+
(new DismissNotice($editor->getDecoratedObject()))();
10485
}
10586

10687
return [
@@ -112,6 +93,7 @@ public function dismiss()
11293
* Validates the 'dismiss' action.
11394
*
11495
* @return void
96+
* @deprecated 6.3
11597
*/
11698
public function validateDismiss()
11799
{
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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.
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(
19+
public readonly Notice $notice
20+
) {}
21+
}
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+
* Dismisses a notice.
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)