-
Notifications
You must be signed in to change notification settings - Fork 145
Expand file tree
/
Copy pathActivateConfig.php
More file actions
199 lines (173 loc) Β· 9.06 KB
/
Copy pathActivateConfig.php
File metadata and controls
199 lines (173 loc) Β· 9.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<?php
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Richdocuments\Command;
use OCA\Richdocuments\AppConfig;
use OCA\Richdocuments\Service\CapabilitiesService;
use OCA\Richdocuments\Service\ConnectivityService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class ActivateConfig extends Command {
public function __construct(
private AppConfig $appConfig,
private ConnectivityService $connectivityService,
private CapabilitiesService $capabilitiesService,
) {
parent::__construct();
}
protected function configure(): void {
$this
->setName('richdocuments:activate-config')
->setAliases(['richdocuments:setup'])
->addOption('wopi-url', 'w', InputOption::VALUE_REQUIRED,
'URL that Nextcloud will use to connect to Collabora', null)
->addOption('builtin', null, InputOption::VALUE_NONE,
'Configure the built-in CODE server (richdocumentscode app must be installed)')
->addOption('callback-url', 'c', InputOption::VALUE_REQUIRED,
'URL that is passed to Collabora to connect back to Nextcloud', null)
->addOption('force', null, InputOption::VALUE_NONE,
'Persist configuration even if connectivity or sanity checks fail')
->setDescription('Activate config changes');
}
protected function execute(InputInterface $input, OutputInterface $output): int {
try {
if ($input->getOption('builtin')) {
return $this->executeBuiltin($input, $output);
}
return $this->executeCustom($input, $output);
} catch (\Exception $e) {
$output->writeln('<error>Failed to activate any config changes</error>');
$output->writeln($e->getMessage());
$output->writeln($e->getTraceAsString());
return 1;
}
}
private function executeBuiltin(InputInterface $input, OutputInterface $output): int {
$force = (bool)$input->getOption('force');
// Validate preconditions before writing anything: getBuiltinServerUrl() checks OS/arch/installed
$builtinUrl = $this->appConfig->getBuiltinServerUrl();
if ($builtinUrl === null) {
$output->writeln('<error>Built-in CODE server is not available.</error>');
$output->writeln('<error>Check: richdocumentscode (or richdocumentscode_arm64) is installed,'
. ' OS is Linux, arch is x86_64 or aarch64.</error>');
return 1;
}
// Validate public URL looks correct before writing anything.
// For builtin, the public URL is always Nextcloud's own origin β derived
// directly from IURLGenerator without requiring server_mode to be set yet.
$publicUrl = $this->appConfig->deriveBuiltinPublicUrl();
// If the derived URL looks internal, overwrite.cli.url is probably wrong.
// Fail fast with an actionable message rather than silently storing a broken value.
// Often will be a false positive warning in test environments, but can be forced if necessary still.
$host = parse_url($publicUrl, PHP_URL_HOST);
$looksInternal = $host === 'localhost' || $host === '127.0.0.1' || str_ends_with($host, '.local');
if ($looksInternal && !$force) {
$output->writeln('<error>Derived public URL looks internal: ' . $publicUrl . '</error>');
$output->writeln('<error>"overwrite.cli.url" in config.php must be set to your public Nextcloud URL.</error>');
$output->writeln('<error>This is required for any occ command that generates absolute URLs.</error>');
$output->writeln('<comment>To override and persist anyway: --force</comment>');
return 1;
}
if ($looksInternal) {
$output->writeln('<comment>β Warning: public URL looks internal (' . $publicUrl . ').'
. ' Proceeding anyway due to --force.</comment>');
}
// Test connectivity against the derived URL directly; no config mutation needed.
if (!$force) {
try {
$this->connectivityService->testUrl($builtinUrl, $output);
} catch (\Throwable $e) {
// Nothing was writtent o config; no rollback needed
$output->writeln('<error>Failed to reach built-in CODE server: ' . $e->getMessage() . '</error>');
$output->writeln('<comment>To configure without connectivity: --force</comment>');
return 1;
}
}
// All checks passed (or --force). Now commit atomically.
$this->appConfig->setAppValue(AppConfig::SERVER_MODE, 'builtin');
$this->appConfig->setAppValue('disable_certificate_verification', 'yes');
// Explicitly delete any previously stored wopi_url and public_wopi_url to avoid ambiguity.
$this->appConfig->setAppValue(AppConfig::WOPI_URL, '');
$this->appConfig->setAppValue(AppConfig::PUBLIC_WOPI_URL, '');
if ($input->getOption('callback-url') !== null) {
$callbackUrl = $input->getOption('callback-url');
$this->appConfig->setAppValue(AppConfig::WOPI_CALLBACK_URL, $callbackUrl);
} else {
$this->appConfig->setAppValue(AppConfig::WOPI_CALLBACK_URL, '');
}
$output->writeln('<info>β Built-in CODE server configured successfully.</info>');
$output->writeln('Built-in CODE URL (Nextcloud β CODE): ' . $this->appConfig->getCollaboraUrlInternal());
$output->writeln('Public URL (browser β CODE): ' . $this->appConfig->getCollaboraUrlPublic());
$callbackUrl = $this->appConfig->getNextcloudUrl();
$output->writeln('Callback URL (Collabora β Nextcloud): '
. ($callbackUrl === '' ? 'autodetected' : $callbackUrl));
return 0;
}
private function executeCustom(InputInterface $input, OutputInterface $output): int {
$force = (bool)$input->getOption('force');
if ($input->getOption('wopi-url') !== null) {
$wopiUrl = $input->getOption('wopi-url');
$this->appConfig->setAppValue(AppConfig::WOPI_URL, $wopiUrl);
$this->appConfig->setAppValue(AppConfig::SERVER_MODE, 'custom');
$output->writeln('<info>β Set WOPI url to ' . $wopiUrl . '</info>');
}
if ($input->getOption('callback-url') !== null) {
$callbackUrl = $input->getOption('callback-url');
$this->appConfig->setAppValue(AppConfig::WOPI_CALLBACK_URL, $callbackUrl);
$output->writeln('<info>β Set callback url to ' . $callbackUrl . '</info>');
} else {
$this->appConfig->setAppValue(AppConfig::WOPI_CALLBACK_URL, '');
$output->writeln('<info>β Reset callback url autodetect</info>');
}
$output->writeln('Checking configuration');
$output->writeln('π Configured WOPI URL: ' . $this->appConfig->getCollaboraUrlInternal());
$output->writeln('π Configured public WOPI URL: ' . $this->appConfig->getCollaboraUrlPublic());
$output->writeln('π Configured callback URL: ' . $this->appConfig->getNextcloudUrl());
$output->writeln('');
if (!$force) {
try {
$this->connectivityService->testDiscovery($output);
} catch (\Throwable $e) {
$output->writeln('<error>Failed to fetch discovery endpoint from '
. $this->appConfig->getCollaboraUrlInternal() . '</error>');
$output->writeln($e->getMessage());
$output->writeln('<comment>To configure without connectivity: --force</comment>');
return 1;
}
try {
$this->connectivityService->testCapabilities($output);
} catch (\Throwable $e) {
$output->writeln('<error>Failed to fetch capabilities from '
. $this->capabilitiesService->getCapabilitiesEndpoint() . '</error>');
$output->writeln($e->getMessage());
$output->writeln('<comment>To configure without connectivity: --force</comment>');
return 1;
}
try {
$this->connectivityService->autoConfigurePublicUrl();
} catch (\Throwable $e) {
$output->writeln('<error>Failed to determine public URL from discovery response</error>');
$output->writeln($e->getMessage());
$output->writeln('<comment>To configure without connectivity: --force</comment>');
return 1;
}
} else {
$output->writeln('<comment>β Skipping connectivity checks (--force).</comment>');
}
$output->writeln('');
$output->writeln('Collabora URL (used for Nextcloud to contact the Collabora server):');
$output->writeln(' ' . $this->appConfig->getCollaboraUrlInternal());
$output->writeln('Collabora public URL (used in the browser to open Collabora):');
$output->writeln(' ' . $this->appConfig->getCollaboraUrlPublic());
$output->writeln('Callback URL (used by Collabora to connect back to Nextcloud):');
$callbackUrl = $this->appConfig->getNextcloudUrl();
$output->writeln($callbackUrl === ''
? ' autodetected (will use the same URL as your user for browsing Nextcloud)'
: ' ' . $callbackUrl);
return 0;
}
}