Files
provider_imap/lib/Console/ServiceDisconnectCommand.php
Sebastian Krupinski e51c65bf19 feat: initial version
Signed-off-by: Sebastian Krupinski <root@LAPTOP-7DVOR6NC>
2026-02-20 21:44:49 +00:00

178 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: Sebastian Krupinski <krupinski01@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace KTXM\ProviderImapMail\Console;
use KTXM\ProviderImapMail\Providers\Provider;
use KTXM\ProviderImapMail\Providers\Service;
use KTXC\SessionTenant;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Remove a stored IMAP service connection.
*
* Looks up the service by its ID (or prompts for one), confirms with the
* operator, then permanently deletes the service document from the store.
*
* Usage:
* bin/console provider_imap_mail:service:disconnect --tenant=t1 --user=u1 <service-id>
*/
#[AsCommand(
name: 'provider_imap_mail:service:disconnect',
description: 'Remove a stored IMAP service connection',
)]
class ServiceDisconnectCommand extends Command
{
public function __construct(
private readonly Provider $provider,
private readonly SessionTenant $sessionTenant,
) {
parent::__construct();
}
protected function configure(): void
{
$this
->addArgument('service-id', InputArgument::OPTIONAL, 'Service ID to remove')
->addOption('tenant', 't', InputOption::VALUE_REQUIRED, 'Tenant ID')
->addOption('user', 'u', InputOption::VALUE_REQUIRED, 'User ID')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Skip confirmation prompt')
->setHelp(<<<'HELP'
The <info>provider_imap_mail:service:disconnect</info> command permanently removes
a stored IMAP service configuration from the store.
Examples:
Interactive (lists services and prompts for ID):
<info>bin/console provider_imap_mail:service:disconnect --tenant=t1 --user=u1</info>
Direct, with confirmation:
<info>bin/console provider_imap_mail:service:disconnect abc123 --tenant=t1 --user=u1</info>
Skip confirmation:
<info>bin/console provider_imap_mail:service:disconnect abc123 --tenant=t1 --user=u1 --force</info>
HELP);
}
protected function interact(InputInterface $input, OutputInterface $output): void
{
$io = new SymfonyStyle($input, $output);
if (!$input->getOption('tenant')) {
$tenant = $io->ask('Tenant ID');
if ($tenant) $input->setOption('tenant', $tenant);
}
if (!$input->getOption('user')) {
$user = $io->ask('User ID');
if ($user) $input->setOption('user', $user);
}
// If no service ID given, list available services and let the operator pick
if (!$input->getArgument('service-id')) {
$tenantId = (string) ($input->getOption('tenant') ?? '');
$userId = (string) ($input->getOption('user') ?? '');
if ($tenantId !== '' && $userId !== '') {
$this->sessionTenant->configureById($tenantId);
$services = $this->provider->serviceList($tenantId, $userId);
if (empty($services)) {
// nothing to select — let execute() handle the error
return;
}
$choices = [];
foreach ($services as $id => $service) {
$label = $service instanceof Service ? ($service->getLabel() ?? $id) : $id;
$choices[$id] = "{$label} [{$id}]";
}
$chosen = $io->choice('Select service to disconnect', array_values($choices));
// resolve the chosen label back to its key
$serviceId = (string) array_search($chosen, $choices, true);
if ($serviceId !== '') {
$input->setArgument('service-id', $serviceId);
}
}
}
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$tenantId = (string) ($input->getOption('tenant') ?? '');
$userId = (string) ($input->getOption('user') ?? '');
$serviceId = (string) ($input->getArgument('service-id') ?? '');
$force = (bool) $input->getOption('force');
$errors = [];
if ($tenantId === '') $errors[] = 'Tenant ID is required (--tenant).';
if ($userId === '') $errors[] = 'User ID is required (--user).';
if ($serviceId === '') $errors[] = 'Service ID is required.';
if (!empty($errors)) {
$io->error($errors);
return Command::FAILURE;
}
// ── Fetch service for display ────────────────────────────────────────
$this->sessionTenant->configureById($tenantId);
$service = $this->provider->serviceFetch($tenantId, $userId, $serviceId);
if ($service === null) {
$io->error("Service '{$serviceId}' not found.");
return Command::FAILURE;
}
$label = $service->getLabel() ?? $serviceId;
$host = $service->getLocation()?->getHost() ?? 'unknown';
$io->title('Disconnect IMAP Service');
$io->definitionList(
['ID' => $serviceId],
['Label' => $label],
['Host' => $host],
);
// ── Confirmation ─────────────────────────────────────────────────────
if (!$force) {
$confirm = $io->confirm(
"Permanently remove service <comment>{$label}</comment> ({$serviceId})?",
false
);
if (!$confirm) {
$io->note('Aborted.');
return Command::SUCCESS;
}
}
// ── Destroy ──────────────────────────────────────────────────────────
$deleted = $this->provider->serviceDestroy($tenantId, $userId, $service);
if (!$deleted) {
$io->error("Failed to remove service '{$serviceId}'.");
return Command::FAILURE;
}
$io->success("Service '{$label}' ({$serviceId}) has been removed.");
return Command::SUCCESS;
}
}