generated from Nodarx/template
feat: implement initial read only access
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace KTXM\ServiceWopi\Console;
|
||||
|
||||
use KTXM\ServiceWopi\Host\SessionStore;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
#[AsCommand(name: 'wopi:cleanup', description: 'Remove expired WOPI sessions and discovery cache records')]
|
||||
class CleanupCommand extends Command
|
||||
{
|
||||
public function __construct(private readonly SessionStore $store) { parent::__construct(); }
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->store->cleanup(time());
|
||||
$output->writeln('Expired WOPI records removed.');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace KTXM\ServiceWopi\Console;
|
||||
|
||||
use KTXC\Service\TenantService;
|
||||
use KTXM\ServiceWopi\Discovery\DiscoveryClient;
|
||||
use KTXM\ServiceWopi\Host\Configuration;
|
||||
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;
|
||||
|
||||
#[AsCommand(name: 'wopi:configure', description: 'Configure tenant office viewing and verify server discovery')]
|
||||
class ConfigureCommand extends Command
|
||||
{
|
||||
public function __construct(private readonly TenantService $tenants, private readonly DiscoveryClient $discovery)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addArgument('tenant', InputArgument::REQUIRED, 'Tenant identifier or domain')
|
||||
->addArgument('office-server', InputArgument::REQUIRED, 'Office server HTTPS base URL')
|
||||
->addOption('origin-server', null, InputOption::VALUE_REQUIRED, 'Application HTTPS origin reachable from the office server (defaults to the tenant domain)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
try {
|
||||
$tenantArgument = $input->getArgument('tenant');
|
||||
$tenant = $this->tenants->fetchById($tenantArgument);
|
||||
$matchedByDomain = $tenant === null;
|
||||
$tenant ??= $this->tenants->fetchByDomain($tenantArgument);
|
||||
if ($tenant === null || !$tenant->getEnabled()) {
|
||||
$io->error('An enabled tenant is required.');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
$origin = $input->getOption('origin-server');
|
||||
if ($origin === null) {
|
||||
$domains = array_values(array_unique($tenant->getDomains()?->getArrayCopy() ?? []));
|
||||
if ($matchedByDomain) {
|
||||
$origin = 'https://' . $tenantArgument;
|
||||
} elseif (count($domains) === 1) {
|
||||
$origin = 'https://' . $domains[0];
|
||||
} else {
|
||||
$io->error('Specify --origin-server or select the tenant by domain; its origin server cannot be determined unambiguously.');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
$wopi = $this->tenants->fetchServiceConfiguration($tenant->getIdentifier(), 'wopi') ?? [];
|
||||
unset($wopi['origin_server']);
|
||||
$wopi = array_replace($wopi, ['enabled' => true, 'office_server' => $input->getArgument('office-server'), 'origin_server' => $origin]);
|
||||
$config = new Configuration($wopi);
|
||||
$document = $this->discovery->fetch($config->office);
|
||||
$viewable = array_filter($document->actions, static fn ($action) => $action->extension === 'docx' && $action->name === 'view' && $action->supportedBy([]));
|
||||
if (!$document->hasProofKeys || $viewable === []) {
|
||||
$io->error('The office server must advertise DOCX viewing and proof keys. Settings were not changed.');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
$wopi['office_server'] = $config->office->url;
|
||||
$wopi['origin_server'] = $config->origin->origin;
|
||||
if ($input->getOption('origin-server') === null && count(array_unique($tenant->getDomains()?->getArrayCopy() ?? [])) === 1) {
|
||||
unset($wopi['origin_server']);
|
||||
}
|
||||
// Preserve the selected origin when a tenant has multiple aliases.
|
||||
if (!$this->tenants->storeServiceConfiguration($tenant->getIdentifier(), 'wopi', $wopi)) {
|
||||
$io->error('Could not save tenant office settings.');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
$io->success('Office viewing configured in the tenant database. Reload the application to register the viewer.');
|
||||
$io->note('The office server must resolve the application hostname and trust its HTTPS certificate. Discovery does not test that return connection.');
|
||||
return Command::SUCCESS;
|
||||
} catch (\Throwable) {
|
||||
$io->error('Configuration failed. Check the tenant, HTTPS URLs, and office discovery.');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user