Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions lib/Command/Bot/ListBots.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
use OCA\Talk\Model\BotConversation;
use OCA\Talk\Model\BotConversationMapper;
use OCA\Talk\Model\BotServerMapper;
use OCA\Talk\Service\BotService;
use OCP\App\IAppManager;
use OCP\AppFramework\Utility\ITimeFactory;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -21,6 +24,9 @@ class ListBots extends Base {
public function __construct(
private BotConversationMapper $botConversationMapper,
private BotServerMapper $botServerMapper,
private BotService $botService,
private IAppManager $appManager,
private ITimeFactory $timeFactory,
) {
parent::__construct();
}
Expand Down Expand Up @@ -58,6 +64,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$botData = $bot->jsonSerialize();
$botData['features'] = Bot::featureFlagsToLabels($botData['features']);

if (!$this->botService->isAppForBotEnabled($bot)) {
$botData['state'] = Bot::STATE_UNAVAILABLE;
if ($input->getOption('output') === 'plain') {
$botData['error_count'] = '<error>' . 1 . '</error>';
} else {
$botData['error_count'] = 1;
}
$botData['last_error_date'] = $this->timeFactory->getTime();
if ($input->getOption('output') === 'plain') {
$botData['last_error_message'] = '<error>App disabled</error>';
} else {
$botData['last_error_message'] = 'App disabled';
}
}

if (!$output->isVerbose()) {
unset($botData['url']);
unset($botData['url_hash']);
Expand Down
7 changes: 7 additions & 0 deletions lib/Command/Bot/Setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use OCA\Talk\Model\BotConversation;
use OCA\Talk\Model\BotConversationMapper;
use OCA\Talk\Model\BotServerMapper;
use OCA\Talk\Service\BotService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\DB\Exception;
use OCP\EventDispatcher\IEventDispatcher;
Expand All @@ -28,6 +29,7 @@ public function __construct(
private Manager $roomManager,
private BotServerMapper $botServerMapper,
private BotConversationMapper $botConversationMapper,
private BotService $botService,
private IEventDispatcher $dispatcher,
) {
parent::__construct();
Expand Down Expand Up @@ -63,6 +65,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 1;
}

if (!$this->botService->isAppForBotEnabled($botServer)) {
$output->writeln('<error>Bot app is disabled: ' . $botServer->getUrl() . '</error>');
return 1;
}

$returnCode = 0;
foreach ($tokens as $token) {
try {
Expand Down
21 changes: 20 additions & 1 deletion lib/Controller/BotController.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use OCP\Comments\MessageTooLongException;
use OCP\Comments\NotFoundException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IL10N;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

Expand All @@ -66,6 +67,7 @@ public function __construct(
protected Manager $manager,
protected ReactionManager $reactionManager,
protected ThreadService $threadService,
protected IL10N $l,
protected LoggerInterface $logger,
private IEventDispatcher $dispatcher,
) {
Expand Down Expand Up @@ -346,6 +348,14 @@ public function adminListBots(): DataResponse {
foreach ($bots as $bot) {
$botData = $bot->jsonSerialize();
unset($botData['secret']);

if (!$this->botService->isAppForBotEnabled($bot)) {
$botData['state'] = Bot::STATE_UNAVAILABLE;
$botData['error_count'] = 1;
$botData['last_error_date'] = $this->timeFactory->getTime();
$botData['last_error_message'] = $this->l->t('App disabled');
}

$data[] = $botData;
}

Expand Down Expand Up @@ -374,6 +384,15 @@ public function listBots(): DataResponse {
$bots = $this->botServerMapper->getAllBots();
foreach ($bots as $bot) {
$botData = $this->formatBot($bot, in_array($bot->getId(), $alreadyInstalled, true));

if (!$this->botService->isAppForBotEnabled($bot)) {
if ($botData['state'] !== Bot::STATE_DISABLED) {
$botData['state'] = Bot::STATE_UNAVAILABLE;
} else {
continue;
}
}

if ($botData !== null) {
$data[] = $botData;
}
Expand Down Expand Up @@ -414,7 +433,7 @@ public function enableBot(int $botId): DataResponse {
], Http::STATUS_BAD_REQUEST);
}

if ($bot->getState() !== Bot::STATE_ENABLED) {
if ($bot->getState() !== Bot::STATE_ENABLED || !$this->botService->isAppForBotEnabled($bot)) {
return new DataResponse([
'error' => 'bot',
], Http::STATUS_BAD_REQUEST);
Expand Down
1 change: 1 addition & 0 deletions lib/Model/Bot.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Bot {
public const STATE_DISABLED = 0;
public const STATE_ENABLED = 1;
public const STATE_NO_SETUP = 2;
public const STATE_UNAVAILABLE = 3;

public const FEATURE_NONE = 0;
public const FEATURE_WEBHOOK = 1;
Expand Down
12 changes: 12 additions & 0 deletions lib/Service/BotService.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use OCA\Talk\Model\BotServerMapper;
use OCA\Talk\Room;
use OCA\Talk\TalkSession;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Comments\IComment;
Expand Down Expand Up @@ -67,6 +68,7 @@ public function __construct(
protected LoggerInterface $logger,
protected ICertificateManager $certificateManager,
protected IEventDispatcher $dispatcher,
protected IAppManager $appManager,
) {
$this->activityPubHelper = new ActivityPubHelper();
}
Expand Down Expand Up @@ -503,4 +505,14 @@ public function validateBotParameters(string $name, string $secret, string $url,
throw new \InvalidArgumentException('The provided description is too long (max. 4000 chars)');
}
}

public function isAppForBotEnabled(BotServer $bot): bool {
if (!str_starts_with($bot->getUrl(), Bot::URL_APP_PREFIX)) {
return true;
}

$url = substr($bot->getUrl(), strlen(Bot::URL_APP_PREFIX));
[$appId] = explode('/', $url, 2);
return $this->appManager->isEnabledForAnyone($appId);
}
}
2 changes: 2 additions & 0 deletions src/components/AdminSettings/BotsSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ export default {
return { state_icon_component: IconLockOutline, state_icon_label: t('spreed', 'Locked for moderators'), state_icon_color: 'var(--color-favorite)' }
case BOT.STATE.ENABLED:
return { state_icon_component: IconCheck, state_icon_label: t('spreed', 'Enabled'), state_icon_color: 'var(--color-border-success)' }
case BOT.STATE.UNAVAILABLE:
return { state_icon_component: IconCancel, state_icon_label: t('spreed', 'App disabled'), state_icon_color: 'var(--color-text-maxcontrast)' }
case BOT.STATE.DISABLED:
default:
return { state_icon_component: IconCancel, state_icon_label: t('spreed', 'Disabled'), state_icon_color: 'var(--color-border-error)' }
Expand Down
28 changes: 27 additions & 1 deletion src/components/ConversationSettings/BotsSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@
<span class="bots-settings__item-description">
{{ bot.description ?? t('spreed', 'Description is not provided') }}
</span>
<NcNoteCard v-if="isBotUnavailable(bot)" type="warning">
<template #icon>
<IconCancel :size="20" />
</template>
{{ t('spreed', 'The bot is not available anymore') }}
</NcNoteCard>
</div>
<div v-if="isLoading[bot.id]" class="bots-settings__item-loader icon icon-loading-small" />
<NcButton
class="bots-settings__item-button"
:variant="bot.state ? 'primary' : 'secondary'"
:variant="buttonType(bot)"
:disabled="isBotLocked(bot) || isLoading[bot.id]"
@click="toggleBotState(bot)">
{{ toggleButtonTitle(bot) }}
Expand All @@ -38,6 +44,8 @@
<script>
import { t } from '@nextcloud/l10n'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
import IconCancel from 'vue-material-design-icons/Cancel.vue'
import { BOT } from '../../constants.ts'
import { useBotsStore } from '../../stores/bots.ts'

Expand All @@ -46,6 +54,8 @@ export default {

components: {
NcButton,
NcNoteCard,
IconCancel,
},

props: {
Expand Down Expand Up @@ -96,6 +106,10 @@ export default {
return bot.state === BOT.STATE.NO_SETUP
},

isBotUnavailable(bot) {
return bot.state === BOT.STATE.UNAVAILABLE
},

async toggleBotState(bot) {
if (this.isBotLocked(bot)) {
return
Expand All @@ -105,7 +119,19 @@ export default {
this.isLoading[bot.id] = false
},

buttonType(bot) {
if (this.isBotUnavailable(bot)) {
return 'warning'
}

return bot.state === BOT.STATE.ENABLED ? 'primary' : 'secondary'
},

toggleButtonTitle(bot) {
if (this.isBotUnavailable(bot)) {
return t('spreed', 'Disable')
}

if (this.isBotLocked(bot)) {
return t('spreed', 'Enabled')
}
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ export const BOT = {
DISABLED: 0,
ENABLED: 1,
NO_SETUP: 2,
UNAVAILABLE: 3,
},
} as const

Expand Down
Loading