diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml
index eb3fa0a..47b8f6a 100644
--- a/.github/workflows/codestyle.yml
+++ b/.github/workflows/codestyle.yml
@@ -13,7 +13,7 @@ jobs:
- name: Setup PHP with tools
uses: shivammathur/setup-php@v2
with:
- php-version: '8.0'
+ php-version: '8.3'
extensions: ctype, dom, exif, gd, gmp, hash, intl, json, libxml, mbstring, opcache, pcre, pdo, pdo_mysql, zlib
tools: cs2pr, phpcs, php-cs-fixer
- name: phpcs
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index dc44d63..49050ac 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -15,6 +15,7 @@ jobs:
- '8.1'
- '8.2'
- '8.3'
+ - '8.4'
steps:
- name: Set up PHP
uses: shivammathur/setup-php@v2
diff --git a/acpMenu.xml b/acpMenu.xml
deleted file mode 100644
index 4f0d60c..0000000
--- a/acpMenu.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/acpTemplateDelete.xml b/acpTemplateDelete.xml
deleted file mode 100644
index 5cc13e3..0000000
--- a/acpTemplateDelete.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- __discordSecretFormField
-
-
diff --git a/acptemplates/discordBotList.tpl b/acptemplates/discordBotList.tpl
index 88ec652..47293f7 100644
--- a/acptemplates/discordBotList.tpl
+++ b/acptemplates/discordBotList.tpl
@@ -13,80 +13,8 @@
-{hascontent}
-
-{/hascontent}
-
-{if $objects|count}
-
-
-
-{else}
- {lang}wcf.global.noItems{/lang}
-{/if}
+
+ {unsafe:$gridView->render()}
+
{include file='footer'}
\ No newline at end of file
diff --git a/acptemplates/discordWebhookList.tpl b/acptemplates/discordWebhookList.tpl
index 5e5774a..f495db5 100644
--- a/acptemplates/discordWebhookList.tpl
+++ b/acptemplates/discordWebhookList.tpl
@@ -6,91 +6,8 @@
-{hascontent}
-
-{/hascontent}
-
-{if $objects|count}
-
-
-
-{else}
- {lang}wcf.global.noItems{/lang}
-{/if}
+
+ {unsafe:$gridView->render()}
+
{include file='footer'}
\ No newline at end of file
diff --git a/fileDelete.xml b/fileDelete.xml
deleted file mode 100644
index fb7f12a..0000000
--- a/fileDelete.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
- files/lib/system/discord/SecretFormField.class.php
-
-
diff --git a/files/lib/acp/page/DiscordBotListPage.class.php b/files/lib/acp/page/DiscordBotListPage.class.php
index daf1977..82b81fc 100644
--- a/files/lib/acp/page/DiscordBotListPage.class.php
+++ b/files/lib/acp/page/DiscordBotListPage.class.php
@@ -2,8 +2,10 @@
namespace wcf\acp\page;
-use wcf\data\discord\bot\DiscordBotList;
-use wcf\page\SortablePage;
+use Override;
+use wcf\page\AbstractGridViewPage;
+use wcf\system\gridView\AbstractGridView;
+use wcf\system\gridView\admin\DiscordBotGridView;
/**
* Übersicht aller Discord-Bots
@@ -13,7 +15,7 @@
* @license Freie Lizenz (https://hanashi.dev/freie-lizenz/)
* @package WoltLabSuite\Core\Acp\Page
*/
-class DiscordBotListPage extends SortablePage
+final class DiscordBotListPage extends AbstractGridViewPage
{
/**
* @inheritDoc
@@ -25,23 +27,9 @@ class DiscordBotListPage extends SortablePage
*/
public $activeMenuItem = 'wcf.acp.menu.link.configuration.discord.discordBotList';
- /**
- * @inheritDoc
- */
- public $objectListClassName = DiscordBotList::class;
-
- /**
- * @inheritDoc
- */
- public $defaultSortField = 'botID';
-
- /**
- * @inheritDoc
- */
- public $defaultSortOrder = 'ASC';
-
- /**
- * @inheritDoc
- */
- public $validSortFields = ['botID', 'botName', 'guildID', 'guildName', 'botTime'];
+ #[Override]
+ protected function createGridView(): AbstractGridView
+ {
+ return new DiscordBotGridView();
+ }
}
diff --git a/files/lib/acp/page/DiscordWebhookListPage.class.php b/files/lib/acp/page/DiscordWebhookListPage.class.php
index c375136..e399910 100644
--- a/files/lib/acp/page/DiscordWebhookListPage.class.php
+++ b/files/lib/acp/page/DiscordWebhookListPage.class.php
@@ -3,10 +3,9 @@
namespace wcf\acp\page;
use Override;
-use wcf\data\discord\webhook\DiscordWebhookList;
-use wcf\page\SortablePage;
-use wcf\system\cache\builder\DiscordGuildChannelsCacheBuilder;
-use wcf\system\WCF;
+use wcf\page\AbstractGridViewPage;
+use wcf\system\gridView\AbstractGridView;
+use wcf\system\gridView\admin\DiscordWebhookGridView;
/**
* Übersicht der erstellten Discord-Webhooks
@@ -16,7 +15,7 @@
* @license Freie Lizenz (https://hanashi.dev/freie-lizenz/)
* @package WoltLabSuite\Core\Acp\Page
*/
-class DiscordWebhookListPage extends SortablePage
+final class DiscordWebhookListPage extends AbstractGridViewPage
{
/**
* @inheritDoc
@@ -28,43 +27,9 @@ class DiscordWebhookListPage extends SortablePage
*/
public $activeMenuItem = 'wcf.acp.menu.link.configuration.discord.discordWebhookList';
- /**
- * @inheritDoc
- */
- public $objectListClassName = DiscordWebhookList::class;
-
- /**
- * @inheritDoc
- */
- public $defaultSortField = 'webhookID';
-
- /**
- * @inheritDoc
- */
- public $defaultSortOrder = 'ASC';
-
- /**
- * @inheritDoc
- */
- public $validSortFields = ['channelID', 'botID', 'webhookID', 'webhookName', 'webhookTitle', 'webhookTime'];
-
- protected array $channels = [];
-
#[Override]
- public function readData()
+ protected function createGridView(): AbstractGridView
{
- parent::readData();
-
- $this->channels = DiscordGuildChannelsCacheBuilder::getInstance()->getData();
- }
-
- #[Override]
- public function assignVariables()
- {
- parent::assignVariables();
-
- WCF::getTPL()->assign([
- 'channels' => $this->channels,
- ]);
+ return new DiscordWebhookGridView();
}
}
diff --git a/files/lib/bootstrap/dev.hanashi.wsc.discord-api.php b/files/lib/bootstrap/dev.hanashi.wsc.discord-api.php
index 725d164..2a60665 100644
--- a/files/lib/bootstrap/dev.hanashi.wsc.discord-api.php
+++ b/files/lib/bootstrap/dev.hanashi.wsc.discord-api.php
@@ -5,7 +5,10 @@
use wcf\acp\page\DiscordWebhookListPage;
use wcf\event\acp\dashboard\box\PHPExtensionCollecting;
use wcf\event\acp\menu\item\ItemCollecting;
+use wcf\event\endpoint\ControllerCollecting;
use wcf\event\worker\RebuildWorkerCollecting;
+use wcf\system\endpoint\controller\hanashi\discord\bot\DeleteBot;
+use wcf\system\endpoint\controller\hanashi\discord\webhook\DeleteWebhook;
use wcf\system\event\EventHandler;
use wcf\system\menu\acp\AcpMenuItem;
use wcf\system\request\LinkHandler;
@@ -77,4 +80,12 @@ static function (RebuildWorkerCollecting $event) {
$event->register(DiscordWebhookAvatarRebuildDataWorker::class, 0);
}
);
+
+ EventHandler::getInstance()->register(
+ ControllerCollecting::class,
+ static function (ControllerCollecting $event) {
+ $event->register(new DeleteBot());
+ $event->register(new DeleteWebhook());
+ }
+ );
};
diff --git a/files/lib/event/interaction/admin/DiscordBotInteractionCollecting.class.php b/files/lib/event/interaction/admin/DiscordBotInteractionCollecting.class.php
new file mode 100644
index 0000000..e9676ff
--- /dev/null
+++ b/files/lib/event/interaction/admin/DiscordBotInteractionCollecting.class.php
@@ -0,0 +1,13 @@
+checkPermissions(['admin.discord.canManageConnection']);
+
+ $action = new DiscordBotAction([$bot], 'delete');
+ $action->executeAction();
+
+ return new JsonResponse([]);
+ }
+}
diff --git a/files/lib/system/endpoint/controller/hanashi/discord/webhook/DeleteWebhook.class.php b/files/lib/system/endpoint/controller/hanashi/discord/webhook/DeleteWebhook.class.php
new file mode 100644
index 0000000..9473576
--- /dev/null
+++ b/files/lib/system/endpoint/controller/hanashi/discord/webhook/DeleteWebhook.class.php
@@ -0,0 +1,31 @@
+checkPermissions(['admin.discord.canManageWebhooks']);
+
+ $action = new DiscordWebhookAction([$bot], 'delete');
+ $action->executeAction();
+
+ return new JsonResponse([]);
+ }
+}
diff --git a/files/lib/system/gridView/admin/DiscordBotGridView.class.php b/files/lib/system/gridView/admin/DiscordBotGridView.class.php
new file mode 100644
index 0000000..6705418
--- /dev/null
+++ b/files/lib/system/gridView/admin/DiscordBotGridView.class.php
@@ -0,0 +1,91 @@
+addColumns([
+ GridViewColumn::for('botID')
+ ->label('wcf.global.objectID')
+ ->renderer(new ObjectIdColumnRenderer())
+ ->sortable(),
+ GridViewColumn::for('botName')
+ ->label('wcf.acp.discordBotList.botName')
+ ->sortable()
+ ->titleColumn()
+ ->filter(new TextFilter()),
+ GridViewColumn::for('guildName')
+ ->label('wcf.acp.discordBotList.server')
+ ->renderer([
+ new class extends DefaultColumnRenderer {
+ public function render(mixed $value, mixed $context = null): string
+ {
+ \assert($context instanceof DiscordBot);
+
+ $content = '';
+ if (!empty($context->guildIcon)) {
+ $content = \sprintf(
+ '
',
+ $context->guildID,
+ $context->guildIcon
+ );
+ }
+
+ return $content . $context->guildName;
+ }
+ },
+ ])
+ ->sortable()
+ ->filter(new TextFilter()),
+ GridViewColumn::for('botTime')
+ ->label('wcf.global.date')
+ ->renderer(new TimeColumnRenderer())
+ ->sortable()
+ ->filter(new TimeFilter()),
+ ]);
+
+ $provider = new DiscordBotInteractions();
+ $provider->addInteractions([
+ new Divider(),
+ new EditInteraction(DiscordBotEditForm::class),
+ ]);
+ $this->setInteractionProvider($provider);
+
+ $this->setSortField('botID');
+ $this->setSortOrder('ASC');
+ }
+
+ #[Override]
+ public function isAccessible(): bool
+ {
+ return WCF::getSession()->getPermission('admin.discord.canManageConnection');
+ }
+
+ #[Override]
+ protected function createObjectList(): DatabaseObjectList
+ {
+ return new DiscordBotList();
+ }
+}
diff --git a/files/lib/system/gridView/admin/DiscordWebhookGridView.class.php b/files/lib/system/gridView/admin/DiscordWebhookGridView.class.php
new file mode 100644
index 0000000..fade96e
--- /dev/null
+++ b/files/lib/system/gridView/admin/DiscordWebhookGridView.class.php
@@ -0,0 +1,99 @@
+addColumns([
+ GridViewColumn::for('webhookID')
+ ->label('wcf.global.objectID')
+ ->sortable(),
+ GridViewColumn::for('channelID')
+ ->label('wcf.acp.discordWebhookList.channelID')
+ ->renderer([
+ new class extends DefaultColumnRenderer {
+ public function render(mixed $value, mixed $context = null): string
+ {
+ \assert($context instanceof DiscordWebhook);
+
+ $channels = DiscordGuildChannelsCacheBuilder::getInstance()->getData();
+
+ if (!isset($channels[$context->botID][$value])) {
+ return $value;
+ }
+
+ return \sprintf('%s
(%s)', $channels[$context->botID][$value]['name'], $value);
+ }
+ },
+ ])
+ ->sortable(),
+ GridViewColumn::for('webhookTitle')
+ ->label('wcf.acp.discordWebhookList.webhookTitle')
+ ->titleColumn()
+ ->sortable()
+ ->filter(new TextFilter()),
+ GridViewColumn::for('webhookName')
+ ->label('wcf.acp.discordWebhookList.webhookName')
+ ->sortable()
+ ->filter(new TextFilter()),
+ GridViewColumn::for('botID')
+ ->label('wcf.acp.discordBotList.server')
+ ->renderer([
+ new class extends DefaultColumnRenderer {
+ public function render(mixed $value, mixed $context = null): string
+ {
+ \assert($context instanceof DiscordWebhook);
+
+ $bot = $context->getDiscordBot();
+
+ $content = '';
+ if (!empty($bot->guildIcon)) {
+ $content = \sprintf(
+ '
',
+ $bot->guildID,
+ $bot->guildIcon
+ );
+ }
+
+ return $content . $bot->guildName;
+ }
+ },
+ ]),
+ GridViewColumn::for('webhookTime')
+ ->label('wcf.global.date')
+ ->renderer(new TimeColumnRenderer())
+ ->sortable()
+ ->filter(new TimeFilter()),
+ ]);
+
+ $provider = new DiscordWebhookInteractions();
+ $this->setInteractionProvider($provider);
+
+ $this->setSortField('webhookID');
+ $this->setSortOrder('ASC');
+ }
+
+ #[Override]
+ protected function createObjectList(): DatabaseObjectList
+ {
+ return new DiscordWebhookList();
+ }
+}
diff --git a/files/lib/system/interaction/admin/DiscordBotInteractions.class.php b/files/lib/system/interaction/admin/DiscordBotInteractions.class.php
new file mode 100644
index 0000000..065f4e3
--- /dev/null
+++ b/files/lib/system/interaction/admin/DiscordBotInteractions.class.php
@@ -0,0 +1,30 @@
+addInteractions([
+ new DeleteInteraction('hanashi/discord/bot/%s'),
+ ]);
+
+ EventHandler::getInstance()->fire(
+ new DiscordBotInteractionCollecting($this)
+ );
+ }
+
+ #[Override]
+ public function getObjectClassName(): string
+ {
+ return DiscordBot::class;
+ }
+}
diff --git a/files/lib/system/interaction/admin/DiscordWebhookInteractions.class.php b/files/lib/system/interaction/admin/DiscordWebhookInteractions.class.php
new file mode 100644
index 0000000..0055802
--- /dev/null
+++ b/files/lib/system/interaction/admin/DiscordWebhookInteractions.class.php
@@ -0,0 +1,30 @@
+addInteractions([
+ new DeleteInteraction('hanashi/discord/webhook/%s'),
+ ]);
+
+ EventHandler::getInstance()->fire(
+ new DiscordWebhookInteractionCollecting($this)
+ );
+ }
+
+ #[Override]
+ public function getObjectClassName(): string
+ {
+ return DiscordBot::class;
+ }
+}
diff --git a/package.xml b/package.xml
index 7c15d1e..46100de 100644
--- a/package.xml
+++ b/package.xml
@@ -6,8 +6,8 @@
Discord-API
API to cummincate with Discord.
API um mit Discord zu kommunizieren.
- 2.7.2
- 2024-10-22
+ 2.8.0
+ 2025-07-02
https://creativecommons.org/publicdomain/zero/1.0/deed.en
@@ -15,7 +15,7 @@
https://hanashi.dev/
- com.woltlab.wcf
+ com.woltlab.wcf
com.woltlab.wcf
@@ -26,25 +26,14 @@
-
acp/database/install_dev.hanashi.wsc.discord-api.php
-
-
-
-
+
-
-
-
-
-
-
- acp/database/install_dev.hanashi.wsc.discord-api.php