diff --git a/wcfsetup/install/files/acp/templates/noticeList.tpl b/wcfsetup/install/files/acp/templates/noticeList.tpl
index c3d7a15e4c2..5c30518be68 100644
--- a/wcfsetup/install/files/acp/templates/noticeList.tpl
+++ b/wcfsetup/install/files/acp/templates/noticeList.tpl
@@ -1,22 +1,17 @@
{include file='header' pageTitle='wcf.acp.notice.list'}
-
-
-{hascontent}
-
-{/hascontent}
+
+ {unsafe:$gridView->render()}
+
-{if $objects|count}
-
-
- {foreach from=$objects item='notice'}
- -
-
- {$notice->noticeName}
-
-
-
- {icon name='arrows-up-down-left-right'}
-
- {objectAction action="toggle" isDisabled=$notice->isDisabled}
- {icon name='pencil'}
- {objectAction action="delete" objectTitle=$notice->noticeName}
-
- {event name='itemButtons'}
-
-
-
- {/foreach}
-
-
-
-
-
-
-
-
-{else}
- {lang}wcf.global.noItems{/lang}
+{if $gridView->countRows() > 1}
+
{/if}
{include file='footer'}
diff --git a/wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php b/wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php
index f61d91c45fd..9b733f8417d 100644
--- a/wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php
+++ b/wcfsetup/install/files/lib/acp/page/NoticeListPage.class.php
@@ -2,8 +2,9 @@
namespace wcf\acp\page;
-use wcf\data\notice\NoticeList;
-use wcf\page\SortablePage;
+use wcf\page\AbstractGridViewPage;
+use wcf\system\gridView\AbstractGridView;
+use wcf\system\gridView\admin\NoticeGridView;
/**
* Lists the available notices.
@@ -12,32 +13,23 @@
* @copyright 2001-2019 WoltLab GmbH
* @license GNU Lesser General Public License
*
- * @extends SortablePage
+ * @extends AbstractGridViewPage
*/
-class NoticeListPage extends SortablePage
+class NoticeListPage extends AbstractGridViewPage
{
/**
* @inheritDoc
*/
public $activeMenuItem = 'wcf.acp.menu.link.notice.list';
- /**
- * @inheritDoc
- */
- public $defaultSortField = 'showOrder';
-
/**
* @inheritDoc
*/
public $neededPermissions = ['admin.notice.canManageNotice'];
- /**
- * @inheritDoc
- */
- public $objectListClassName = NoticeList::class;
-
- /**
- * @inheritDoc
- */
- public $validSortFields = ['noticeID', 'noticeName', 'showOrder'];
+ #[\Override]
+ protected function createGridView(): AbstractGridView
+ {
+ return new NoticeGridView();
+ }
}
diff --git a/wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php b/wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php
index 8e746d39af3..97fb3f812b6 100644
--- a/wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php
+++ b/wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php
@@ -222,6 +222,11 @@ static function (\wcf\event\endpoint\ControllerCollecting $event) {
$event->register(new \wcf\system\endpoint\controller\core\ads\DeleteAd());
$event->register(new \wcf\system\endpoint\controller\core\ads\GetShowOrder());
$event->register(new \wcf\system\endpoint\controller\core\ads\ChangeShowOrder());
+ $event->register(new \wcf\system\endpoint\controller\core\notices\EnableNotice());
+ $event->register(new \wcf\system\endpoint\controller\core\notices\DisableNotice());
+ $event->register(new \wcf\system\endpoint\controller\core\notices\DeleteNotice());
+ $event->register(new \wcf\system\endpoint\controller\core\notices\GetShowOrder());
+ $event->register(new \wcf\system\endpoint\controller\core\notices\ChangeShowOrder());
}
);
diff --git a/wcfsetup/install/files/lib/data/notice/NoticeAction.class.php b/wcfsetup/install/files/lib/data/notice/NoticeAction.class.php
index 467a2487ce0..325174eea6c 100644
--- a/wcfsetup/install/files/lib/data/notice/NoticeAction.class.php
+++ b/wcfsetup/install/files/lib/data/notice/NoticeAction.class.php
@@ -3,11 +3,9 @@
namespace wcf\data\notice;
use wcf\data\AbstractDatabaseObjectAction;
-use wcf\data\ISortableAction;
use wcf\data\IToggleAction;
use wcf\data\TDatabaseObjectToggle;
use wcf\system\condition\ConditionHandler;
-use wcf\system\exception\UserInputException;
use wcf\system\user\storage\UserStorageHandler;
use wcf\system\WCF;
@@ -20,7 +18,7 @@
*
* @extends AbstractDatabaseObjectAction
*/
-class NoticeAction extends AbstractDatabaseObjectAction implements ISortableAction, IToggleAction
+class NoticeAction extends AbstractDatabaseObjectAction implements IToggleAction
{
use TDatabaseObjectToggle;
@@ -121,27 +119,6 @@ public function validateDismiss()
$this->getSingleObject();
}
- /**
- * @inheritDoc
- */
- public function validateUpdatePosition()
- {
- WCF::getSession()->checkPermissions($this->permissionsUpdate);
-
- if (!isset($this->parameters['data']['structure']) || !\is_array($this->parameters['data']['structure'])) {
- throw new UserInputException('structure');
- }
-
- $noticeList = new NoticeList();
- $noticeList->setObjectIDs($this->parameters['data']['structure'][0]);
- $noticeList->readObjects();
- if (\count($noticeList) !== \count($this->parameters['data']['structure'][0])) {
- throw new UserInputException('structure');
- }
-
- $this->readInteger('offset', true, 'data');
- }
-
/**
* @inheritDoc
*/
@@ -157,25 +134,4 @@ public function update()
\reset($this->objects)->setShowOrder($this->parameters['data']['showOrder']);
}
}
-
- /**
- * @inheritDoc
- */
- public function updatePosition()
- {
- $sql = "UPDATE wcf1_notice
- SET showOrder = ?
- WHERE noticeID = ?";
- $statement = WCF::getDB()->prepare($sql);
-
- $showOrder = $this->parameters['data']['offset'];
- WCF::getDB()->beginTransaction();
- foreach ($this->parameters['data']['structure'][0] as $noticeID) {
- $statement->execute([
- $showOrder++,
- $noticeID,
- ]);
- }
- WCF::getDB()->commitTransaction();
- }
}
diff --git a/wcfsetup/install/files/lib/event/interaction/admin/NoticeInteractionCollecting.class.php b/wcfsetup/install/files/lib/event/interaction/admin/NoticeInteractionCollecting.class.php
new file mode 100644
index 00000000000..4f5353eee86
--- /dev/null
+++ b/wcfsetup/install/files/lib/event/interaction/admin/NoticeInteractionCollecting.class.php
@@ -0,0 +1,21 @@
+
+ * @since 6.2
+ */
+final class NoticeInteractionCollecting implements IPsr14Event
+{
+ public function __construct(public readonly NoticeInteractions $param)
+ {
+ }
+}
diff --git a/wcfsetup/install/files/lib/event/interaction/bulk/admin/NoticeBulkInteractionCollecting.class.php b/wcfsetup/install/files/lib/event/interaction/bulk/admin/NoticeBulkInteractionCollecting.class.php
new file mode 100644
index 00000000000..215f15a9667
--- /dev/null
+++ b/wcfsetup/install/files/lib/event/interaction/bulk/admin/NoticeBulkInteractionCollecting.class.php
@@ -0,0 +1,21 @@
+
+ * @since 6.2
+ */
+final class NoticeBulkInteractionCollecting implements IPsr14Event
+{
+ public function __construct(public readonly NoticeBulkInteractions $param)
+ {
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/ChangeShowOrder.class.php b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/ChangeShowOrder.class.php
new file mode 100644
index 00000000000..3d4031c2d32
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/ChangeShowOrder.class.php
@@ -0,0 +1,68 @@
+
+ * @since 6.2
+ */
+#[PostRequest('/core/notices/show-order')]
+final class ChangeShowOrder implements IController
+{
+ public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
+ {
+ WCF::getSession()->checkPermissions(['admin.notice.canManageNotice']);
+
+ $noticeList = new NoticeList();
+ $noticeList->sqlOrderBy = 'showOrder ASC';
+ $noticeList->readObjects();
+
+ $items = \array_map(
+ static fn(Notice $notice) => new ShowOrderItem($notice->noticeID, $notice->getTitle()),
+ $noticeList->getObjects()
+ );
+
+ $sortedItems = (new ShowOrderHandler($items))->getSortedItemsFromRequest($request);
+ $this->saveShowOrder($sortedItems);
+
+ return new JsonResponse([]);
+ }
+
+ /**
+ * @param list $items
+ */
+ private function saveShowOrder(array $items): void
+ {
+ WCF::getDB()->beginTransaction();
+ $sql = "UPDATE wcf1_notice
+ SET showOrder = ?
+ WHERE noticeID = ?";
+ $statement = WCF::getDB()->prepare($sql);
+ for ($i = 0, $length = \count($items); $i < $length; $i++) {
+ $statement->execute([
+ $i + 1,
+ $items[$i]->id,
+ ]);
+ }
+ WCF::getDB()->commitTransaction();
+
+ NoticeCacheBuilder::getInstance()->reset();
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/DeleteNotice.class.php b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/DeleteNotice.class.php
new file mode 100644
index 00000000000..f88153833b6
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/DeleteNotice.class.php
@@ -0,0 +1,37 @@
+
+ * @since 6.2
+ */
+#[DeleteRequest("/core/notices/{id:\d+}")]
+final class DeleteNotice implements IController
+{
+ #[\Override]
+ public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
+ {
+ WCF::getSession()->checkPermissions(['admin.notice.canManageNotice']);
+
+ $notice = Helper::fetchObjectFromRequestParameter($variables['id'], Notice::class);
+
+ (new NoticeAction([$notice], 'delete'))->executeAction();
+
+ return new JsonResponse([]);
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/DisableNotice.class.php b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/DisableNotice.class.php
new file mode 100644
index 00000000000..f12e7194594
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/DisableNotice.class.php
@@ -0,0 +1,46 @@
+
+ * @since 6.2
+ */
+#[PostRequest("/core/notices/{id:\d+}/disable")]
+final class DisableNotice implements IController
+{
+ public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
+ {
+ $notice = Helper::fetchObjectFromRequestParameter($variables['id'], Notice::class);
+
+ $this->assertNoticeCanBeDisabled($notice);
+
+ (new NoticeAction([$notice], 'toggle'))->executeAction();
+
+ return new JsonResponse([]);
+ }
+
+ private function assertNoticeCanBeDisabled(Notice $notice): void
+ {
+ WCF::getSession()->checkPermissions(['admin.notice.canManageNotice']);
+
+ if ($notice->isDisabled) {
+ throw new PermissionDeniedException();
+ }
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/EnableNotice.class.php b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/EnableNotice.class.php
new file mode 100644
index 00000000000..2c39f7fe5ee
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/EnableNotice.class.php
@@ -0,0 +1,46 @@
+
+ * @since 6.2
+ */
+#[PostRequest("/core/notices/{id:\d+}/enable")]
+final class EnableNotice implements IController
+{
+ public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
+ {
+ $notice = Helper::fetchObjectFromRequestParameter($variables['id'], Notice::class);
+
+ $this->assertNoticeCanBeEnabled($notice);
+
+ (new NoticeAction([$notice], 'toggle'))->executeAction();
+
+ return new JsonResponse([]);
+ }
+
+ private function assertNoticeCanBeEnabled(Notice $notice): void
+ {
+ WCF::getSession()->checkPermissions(['admin.notice.canManageNotice']);
+
+ if (!$notice->isDisabled) {
+ throw new PermissionDeniedException();
+ }
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/GetShowOrder.class.php b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/GetShowOrder.class.php
new file mode 100644
index 00000000000..60ea8865175
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/endpoint/controller/core/notices/GetShowOrder.class.php
@@ -0,0 +1,41 @@
+
+ * @since 6.2
+ */
+#[GetRequest('/core/notices/show-order')]
+final class GetShowOrder implements IController
+{
+ public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
+ {
+ WCF::getSession()->checkPermissions(['admin.notice.canManageNotice']);
+
+ $noticeList = new NoticeList();
+ $noticeList->sqlOrderBy = 'showOrder ASC';
+ $noticeList->readObjects();
+
+ $items = \array_map(
+ static fn(Notice $notice) => new ShowOrderItem($notice->noticeID, $notice->getTitle()),
+ $noticeList->getObjects()
+ );
+
+ return (new ShowOrderHandler($items))->toJsonResponse();
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/gridView/admin/NoticeGridView.class.php b/wcfsetup/install/files/lib/system/gridView/admin/NoticeGridView.class.php
new file mode 100644
index 00000000000..cb13266672e
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/gridView/admin/NoticeGridView.class.php
@@ -0,0 +1,84 @@
+
+ * @since 6.2
+ *
+ * @extends AbstractGridView
+ */
+final class NoticeGridView extends AbstractGridView
+{
+ public function __construct()
+ {
+ $this->addColumns([
+ GridViewColumn::for('noticeID')
+ ->label('wcf.global.objectID')
+ ->renderer(new ObjectIdColumnRenderer())
+ ->sortable(),
+ GridViewColumn::for('noticeName')
+ ->label('wcf.global.name')
+ ->titleColumn()
+ ->filter(new TextFilter())
+ ->sortable(),
+ GridViewColumn::for('showOrder')
+ ->label('wcf.global.showOrder')
+ ->renderer(new NumberColumnRenderer())
+ ->filter(new NumericFilter())
+ ->sortable(),
+ ]);
+
+ $provider = new NoticeInteractions();
+ $provider->addInteractions([
+ new Divider(),
+ new EditInteraction(NoticeEditForm::class)
+ ]);
+ $this->setInteractionProvider($provider);
+ $this->setBulkInteractionProvider(new NoticeBulkInteractions());
+
+ $this->addQuickInteraction(
+ new ToggleInteraction(
+ 'enable',
+ 'core/notices/%s/enable',
+ 'core/notices/%s/disable'
+ )
+ );
+
+ $this->setSortField("showOrder");
+ $this->addRowLink(new GridViewRowLink(NoticeEditForm::class));
+ }
+
+ #[\Override]
+ public function isAccessible(): bool
+ {
+ return WCF::getSession()->getPermission("admin.notice.canManageNotice");
+ }
+
+ #[\Override]
+ protected function createObjectList(): NoticeList
+ {
+ return new NoticeList();
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/interaction/admin/NoticeInteractions.class.php b/wcfsetup/install/files/lib/system/interaction/admin/NoticeInteractions.class.php
new file mode 100644
index 00000000000..83c790c2d37
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/interaction/admin/NoticeInteractions.class.php
@@ -0,0 +1,37 @@
+
+ * @since 6.2
+ */
+final class NoticeInteractions extends AbstractInteractionProvider
+{
+ public function __construct()
+ {
+ $this->addInteractions([
+ new DeleteInteraction("core/notices/%s"),
+ ]);
+
+ EventHandler::getInstance()->fire(
+ new NoticeInteractionCollecting($this)
+ );
+ }
+
+ #[\Override]
+ public function getObjectClassName(): string
+ {
+ return Notice::class;
+ }
+}
diff --git a/wcfsetup/install/files/lib/system/interaction/bulk/admin/NoticeBulkInteractions.class.php b/wcfsetup/install/files/lib/system/interaction/bulk/admin/NoticeBulkInteractions.class.php
new file mode 100644
index 00000000000..25aab8f4f75
--- /dev/null
+++ b/wcfsetup/install/files/lib/system/interaction/bulk/admin/NoticeBulkInteractions.class.php
@@ -0,0 +1,37 @@
+
+ * @since 6.2
+ */
+final class NoticeBulkInteractions extends AbstractBulkInteractionProvider
+{
+ public function __construct()
+ {
+ $this->addInteractions([
+ new BulkDeleteInteraction('core/notices/%s')
+ ]);
+
+ EventHandler::getInstance()->fire(
+ new NoticeBulkInteractionCollecting($this)
+ );
+ }
+
+ #[\Override]
+ public function getObjectListClassName(): string
+ {
+ return NoticeList::class;
+ }
+}