generated from Nodarx/template
204 lines
7.8 KiB
PHP
204 lines
7.8 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 KTXM\ProviderImapMail\Service\Remote\RemoteService;
|
||
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;
|
||
|
||
/**
|
||
* Live IMAP connection test.
|
||
*
|
||
* Connects to the server using a stored service's credentials, authenticates,
|
||
* and lists the root-level mailboxes with their unread message counts as a
|
||
* quick end-to-end sanity check.
|
||
*
|
||
* Usage:
|
||
* bin/console provider_imap_mail:service:test <service-id> --tenant=t1 --user=u1
|
||
*/
|
||
#[AsCommand(
|
||
name: 'provider_imap_mail:service:test',
|
||
description: 'Test an IMAP service connection and list root mailboxes',
|
||
)]
|
||
class ServiceTestCommand 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 test')
|
||
->addOption('tenant', 't', InputOption::VALUE_REQUIRED, 'Tenant ID')
|
||
->addOption('user', 'u', InputOption::VALUE_REQUIRED, 'User ID')
|
||
->addOption('all', 'a', InputOption::VALUE_NONE, 'List all mailboxes, not just the root level')
|
||
->setHelp(<<<'HELP'
|
||
The <info>provider_imap_mail:service:test</info> command opens a live IMAP
|
||
connection for a stored service, authenticates, and lists the available
|
||
mailboxes together with their message counts.
|
||
|
||
Examples:
|
||
|
||
Test a specific service:
|
||
<info>bin/console provider_imap_mail:service:test abc123 --tenant=t1 --user=u1</info>
|
||
|
||
Interactive (lists services, lets you choose one):
|
||
<info>bin/console provider_imap_mail:service:test --tenant=t1 --user=u1</info>
|
||
|
||
Show all mailboxes (not just top-level):
|
||
<info>bin/console provider_imap_mail:service:test abc123 --tenant=t1 --user=u1 --all</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 (!$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)) {
|
||
$choices = [];
|
||
foreach ($services as $id => $service) {
|
||
$label = $service instanceof Service ? ($service->getLabel() ?? $id) : $id;
|
||
$choices[$id] = "{$label} [{$id}]";
|
||
}
|
||
|
||
$chosen = $io->choice('Select service to test', array_values($choices));
|
||
$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') ?? '');
|
||
$showAll = (bool) $input->getOption('all');
|
||
|
||
$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 stored service ─────────────────────────────────────────────
|
||
|
||
$this->sessionTenant->configureById($tenantId);
|
||
|
||
$service = $this->provider->serviceFetch($tenantId, $userId, $serviceId);
|
||
|
||
if (!($service instanceof Service)) {
|
||
$io->error("Service '{$serviceId}' not found.");
|
||
return Command::FAILURE;
|
||
}
|
||
|
||
$host = $service->getLocation()?->getHost() ?? 'unknown';
|
||
$port = $service->getLocation()?->getPort() ?? 993;
|
||
$enc = $service->getLocation()?->getEncryption() ?? 'ssl';
|
||
|
||
$io->title('IMAP Connection Test');
|
||
$io->definitionList(
|
||
['Service' => $service->getLabel() ?? $serviceId],
|
||
['Host' => $host],
|
||
['Port' => (string) $port],
|
||
['Encryption' => $enc],
|
||
['Username' => $service->getIdentity()?->getIdentity() ?? '–'],
|
||
);
|
||
|
||
// ── Quick single-call test via Provider ──────────────────────────────
|
||
|
||
$io->text('Authenticating…');
|
||
$startTime = microtime(true);
|
||
$testResult = $this->provider->serviceTest($service);
|
||
$latency = (int) round((microtime(true) - $startTime) * 1000);
|
||
|
||
if (!$testResult['success']) {
|
||
$io->error($testResult['message']);
|
||
return Command::FAILURE;
|
||
}
|
||
|
||
$io->success($testResult['message']);
|
||
|
||
// ── Mailbox listing ──────────────────────────────────────────────────
|
||
|
||
$io->text('Fetching mailbox list…');
|
||
|
||
try {
|
||
$wrapper = RemoteService::freshClient($service);
|
||
$mailboxes = $wrapper->mailboxes();
|
||
|
||
$rows = [];
|
||
foreach ($mailboxes as $mailbox) {
|
||
// Filter to root-level only unless --all
|
||
if (!$showAll && substr_count($mailbox->name, $mailbox->hierarchyDelimiter ?: '/') > 0) {
|
||
continue;
|
||
}
|
||
|
||
$selectable = $mailbox->isSelectable() ? '<fg=green>✓</>' : '<fg=yellow>–</>';
|
||
$rows[] = [
|
||
$mailbox->name,
|
||
$selectable,
|
||
];
|
||
}
|
||
|
||
if (empty($rows)) {
|
||
$io->note('No mailboxes found' . ($showAll ? '.' : ' at the root level. Use --all to see all mailboxes.'));
|
||
} else {
|
||
$io->table(['Mailbox', 'Selectable'], $rows);
|
||
$noun = count($rows) === 1 ? 'mailbox' : 'mailboxes';
|
||
$io->text(sprintf('<info>%d</info> %s listed. Latency: <comment>%d ms</comment>.', count($rows), $noun, $latency));
|
||
}
|
||
} catch (\Throwable $e) {
|
||
$io->warning('Could not list mailboxes: ' . $e->getMessage());
|
||
}
|
||
|
||
return Command::SUCCESS;
|
||
}
|
||
}
|