ncp-app: Add options for default_phone_region and maintenance_window_start

Signed-off-by: Tobias Knöppler <6317548+theCalcaholic@users.noreply.github.com>
This commit is contained in:
Tobias Knöppler 2024-02-22 16:17:29 +01:00
parent 869bd6a8f4
commit 860fcbe548
No known key found for this signature in database
GPG Key ID: 3510056072886A8F
9 changed files with 1691 additions and 1217 deletions

View File

@ -10,6 +10,7 @@
return [ return [
'routes' => [ 'routes' => [
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'], ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'settings#save', 'url' => '/api/settings', 'verb' => 'POST'] ['name' => 'settings#saveNcpSettings', 'url' => '/api/settings/ncp', 'verb' => 'POST'],
['name' => 'settings#saveNcSettings', 'url' => '/api/settings/nextcloud', 'verb' => 'POST']
] ]
]; ];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,7 @@ namespace OCA\NextcloudPi\Controller;
use OCA\NextcloudPi\Exceptions\InvalidSettingsException; use OCA\NextcloudPi\Exceptions\InvalidSettingsException;
use OCA\NextcloudPi\Exceptions\SaveSettingsException; use OCA\NextcloudPi\Exceptions\SaveSettingsException;
use OCA\NextcloudPi\Service\SettingsService; use OCA\NextcloudPi\Service\SettingsService;
use OCP\HintException;
use OCP\IRequest; use OCP\IRequest;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\JSONResponse;
@ -26,14 +27,13 @@ class SettingsController extends Controller {
/** /**
* @NoCSRFRequired
* @CORS * @CORS
* *
* @param array $settings * @param array $settings
*/ */
public function save(array $settings): JSONResponse { public function saveNcpSettings(array $settings): JSONResponse {
try { try {
$this->service->saveSettings($settings); $this->service->saveNcpSettings($settings);
return new JSONResponse([]); return new JSONResponse([]);
} catch(InvalidSettingsException $e) { } catch(InvalidSettingsException $e) {
return new JSONResponse(["error" => $e->getMessage()], Http::STATUS_BAD_REQUEST); return new JSONResponse(["error" => $e->getMessage()], Http::STATUS_BAD_REQUEST);
@ -41,6 +41,22 @@ class SettingsController extends Controller {
return new JSONResponse(["error" => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); return new JSONResponse(["error" => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
} }
} }
/**
* @CORS
*
* @param array $settings
*/
public function saveNcSettings(array $settings): JSONResponse {
try {
$this->service->saveNcSettings($settings);
return new JSONResponse([]);
} catch(InvalidSettingsException $e) {
return new JSONResponse(["error" => $e->getMessage()], Http::STATUS_BAD_REQUEST);
} catch(SaveSettingsException|HintException $e) {
return new JSONResponse(["error" => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
} }
?> ?>

View File

@ -6,13 +6,18 @@ namespace OCA\NextcloudPi\Service;
use OCA\NextcloudPi\Exceptions\InvalidSettingsException; use OCA\NextcloudPi\Exceptions\InvalidSettingsException;
use OCA\NextcloudPi\Exceptions\SaveSettingsException; use OCA\NextcloudPi\Exceptions\SaveSettingsException;
use OCP\HintException;
use OCP\IConfig;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class SettingsService { class SettingsService {
private LoggerInterface $logger; private LoggerInterface $logger;
private IConfig $config;
public function __construct(LoggerInterface $logger) {
public function __construct(LoggerInterface $logger, IConfig $config) {
$this->logger = $logger; $this->logger = $logger;
$this->config =$config;
} }
/** /**
@ -42,6 +47,7 @@ class SettingsService {
* @param string $defaults Default value to use if the file can't be loaded * @param string $defaults Default value to use if the file can't be loaded
* @return string * @return string
*/ */
// TODO: return type?
public function getFileContent(string $name, string $defaults): string public function getFileContent(string $name, string $defaults): string
{ {
[$ret, $file_contents, $stderr] = $this->runCommand( "bash -c \"sudo /home/www/ncp-app-bridge.sh file $name\""); [$ret, $file_contents, $stderr] = $this->runCommand( "bash -c \"sudo /home/www/ncp-app-bridge.sh file $name\"");
@ -55,7 +61,7 @@ class SettingsService {
* @throws InvalidSettingsException * @throws InvalidSettingsException
* @throws SaveSettingsException * @throws SaveSettingsException
*/ */
public function saveSettings(array $settings) { public function saveNcpSettings(array $settings) {
$parseBool = function ($val): string { $parseBool = function ($val): string {
return $val ? "yes" : "no"; return $val ? "yes" : "no";
}; };
@ -86,6 +92,39 @@ class SettingsService {
} }
} }
/**
* @throws HintException
* @throws SaveSettingsException
* @throws InvalidSettingsException
*/
public function saveNcSettings(array $settings)
{
foreach ($settings as $k => $value) {
if ($k === 'maintenance_window_start') {
if (!is_numeric($value) || (int)$value < 0 || (int)$value > 23) {
throw new SaveSettingsException("Failed to parse maintenance window start: Make sure it's a number between 0 and 23 (was $value).");
}
$hour = (int)$value;
$this->config->setSystemValue('maintenance_window_start', $hour);
} elseif ($k === 'default_phone_region') {
$this->config->setSystemValue('default_phone_region', $value);
} else {
throw new InvalidSettingsException("key error for '$k'");
}
}
}
/**
* Return Nextcloud system config value (of type string)
* @param string $key
* @return string
*/
public function getSystemConfigValueString(string $key): string {
return $this->config->getSystemValueString($key);
}
private function runCommand(string $cmd): array { private function runCommand(string $cmd): array {
$descriptorSpec = [ $descriptorSpec = [
0 => ["pipe", "r"], 0 => ["pipe", "r"],

View File

@ -8,8 +8,7 @@ use OCP\Settings\ISettings;
class AdminSettings implements ISettings { class AdminSettings implements ISettings {
/** @var SettingsService */ private SettingsService $service;
private $service;
/** /**
@ -23,7 +22,8 @@ class AdminSettings implements ISettings {
/** /**
* @return TemplateResponse * @return TemplateResponse
*/ */
public function getForm() { public function getForm(): TemplateResponse
{
$ncp_config = $this->service->getConfig("ncp", $ncp_config = $this->service->getConfig("ncp",
["nextcloud_version" => "unknown", "php_version" => "unknown", "release" => "unknown"]); ["nextcloud_version" => "unknown", "php_version" => "unknown", "release" => "unknown"]);
$community_config = $this->service->getConfig("ncp-community", $community_config = $this->service->getConfig("ncp-community",
@ -31,14 +31,19 @@ class AdminSettings implements ISettings {
"CANARY" => 'no', "CANARY" => 'no',
"USAGE_SURVEYS" => 'no', "USAGE_SURVEYS" => 'no',
"ADMIN_NOTIFICATIONS" => 'no', "ADMIN_NOTIFICATIONS" => 'no',
"NOTIFICATION_ACCOUNTS" => "" "NOTIFICATION_ACCOUNTS" => ''
]); ]);
$ncp_version = trim($this->service->getFileContent("ncp-version", "unknown")); $ncp_version = trim($this->service->getFileContent("ncp-version", "unknown"));
$default_phone_region = $this->service->getSystemConfigValueString("default_phone_region");
$maintenance_window_start = $this->service->getSystemConfigValueString("maintenance_window_start");
return new TemplateResponse('nextcloudpi', 'admin', [ return new TemplateResponse('nextcloudpi', 'admin', [
'community' => $community_config, 'community' => $community_config,
'ncp' => $ncp_config, 'ncp' => $ncp_config,
'ncp_version' => $ncp_version 'ncp_version' => $ncp_version,
'default_phone_region' => $default_phone_region,
'maintenance_window_start' => $maintenance_window_start
]); ]);
} }

2676
ncp-app/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,11 @@ __webpack_public_path__ = generateFilePath(appName, '', 'js/')
// }) // })
async function saveSettings() { async function saveNcpSettings() {
let settings = collectSettings(); let settings = collectNcpSettings();
console.log("Saving nextcloudpi settings: ", settings); console.log("Saving nextcloudpi settings: ", settings);
try { try {
let response = await axios.post(generateUrl('/apps/nextcloudpi/api/settings'), {settings: settings}) let response = await axios.post(generateUrl('/apps/nextcloudpi/api/settings/ncp'), {settings: settings})
console.log("Saving ncp settings succeeded") console.log("Saving ncp settings succeeded")
return {success: true, error: null} return {success: true, error: null}
} catch (e) { } catch (e) {
@ -35,24 +35,50 @@ async function saveSettings() {
} }
} }
function collectSettings() { async function saveNcSettings() {
let settings = collectNcSettings()
console.log("Saving nextcloud settings: ", settings)
try {
let response = await axios.post(generateUrl('/apps/nextcloudpi/api/settings/nextcloud'), {settings: settings})
console.log("Saving nextcloud settings succeeded")
return {success: true, error: null}
} catch (e) {
console.error(e)
let errMsg = e.response.data.error;
throw Error(`${errMsg ? errMsg : e.message} (HTTP ${e.response.status}`)
}
}
function collectNcpSettings() {
let settings = {}; let settings = {};
document.querySelectorAll("#nextcloudpi input").forEach(element => { document.querySelectorAll("#ncp-settings input").forEach(element => {
if (element.type === "checkbox") { if (element.type === "checkbox") {
settings[element.name] = element.checked; settings[element.name] = element.checked;
} else { } else {
settings[element.name] = element.value; settings[element.name] = element.value;
} }
}); });
return settings; return settings
}
function collectNcSettings() {
let settings = {};
document.querySelectorAll("#ncp-settings-nc input").forEach(element => {
if (element.type === "checkbox") {
settings[element.name] = element.checked;
} else {
settings[element.name] = element.value;
}
})
return settings
} }
window.addEventListener('load', () => { window.addEventListener('load', () => {
console.log("Listening to ncp settings changes"); console.log("Listening to ncp settings changes");
let errorBox = document.querySelector("#nextcloudpi .error-message"); let errorBox = document.querySelector("#nextcloudpi .error-message");
document.querySelectorAll("#nextcloudpi input").forEach(element => { document.querySelectorAll("#ncp-settings input").forEach(element => {
element.addEventListener("change", async () => { element.addEventListener("change", async () => {
saveSettings() saveNcpSettings()
.then(() => { .then(() => {
errorBox.classList.add("hidden"); errorBox.classList.add("hidden");
}) })
@ -63,4 +89,17 @@ window.addEventListener('load', () => {
}) })
}) })
}) })
document.querySelectorAll("#ncp-settings-nc input").forEach(element => {
element.addEventListener("change", async () => {
saveNcSettings()
.then(() => {
errorBox.classList.add("hidden")
})
.catch(e => {
console.error(e)
errorBox.innerText = "Failed to save Nextcloud settings: " + e.message
errorBox.classList.remove("hidden")
})
})
})
}) })

View File

@ -8,28 +8,44 @@ style('nextcloudpi', 'admin');
<h3>System Info</h3> <h3>System Info</h3>
<ul> <ul>
<li> <li>
<div>NCP Version:</div><div><?php echo $_["ncp_version"] ?></div> <div>NCP Version:</div>
<div><?php echo $_["ncp_version"] ?></div>
</li> </li>
<li> <li>
<div>PHP Version:</div><div><?php echo $_["ncp"]["php_version"] ?></div> <div>PHP Version:</div>
<div><?php echo $_["ncp"]["php_version"] ?></div>
</li> </li>
<li> <li>
<div>Debian Release:</div><div><?php echo $_["ncp"]["release"] ?></div> <div>Debian Release:</div>
<div><?php echo $_["ncp"]["release"] ?></div>
</li> </li>
</ul> </ul>
<h3>Settings</h3> <h3>Nextcloud Settings</h3>
<ul> <ul id="ncp-settings-nc">
<li>
<input name="maintenance_window_start" type="number" value="<?php echo $_['maintenance_window_start']; ?>"/>
<label for="maintenance_window_start">Maintenance Window Start Hour</label>
</li>
<li>
<input name="default_phone_region" type="text" value="<?php echo $_['default_phone_region']; ?>"/>
<label for="default_phone_region">Default Phone Region</label>
</li>
</ul>
<h3>NCP Settings</h3>
<ul id="ncp-settings">
<li> <li>
<input name="canary" type="checkbox" <?php echo $_['community']['CANARY'] === 'yes' ? ' checked="checked"' : ''; ?>"/> <input name="canary" type="checkbox" <?php echo $_['community']['CANARY'] === 'yes' ? ' checked="checked"' : ''; ?>"/>
<label for="canary">Enable updates from canary (testing) channel</label> <label for="canary">Enable updates from canary (testing) channel</label>
</li> </li>
<li> <li>
<input name="adminNotifications" type="checkbox" <?php echo $_['community']['ADMIN_NOTIFICATIONS'] === 'yes' ? ' checked="checked"' : ''; ?>"/> <input name="adminNotifications"
type="checkbox" <?php echo $_['community']['ADMIN_NOTIFICATIONS'] === 'yes' ? ' checked="checked"' : ''; ?>"/>
<label for="adminNotifications">Enable notifications about relevant changes in NCP</label> <label for="adminNotifications">Enable notifications about relevant changes in NCP</label>
</li> </li>
<li> <li>
<input name="usageSurveys" type="checkbox" <?php echo $_['community']['USAGE_SURVEYS'] === 'yes' ? ' checked="checked"' : ''; ?>"/> <input name="usageSurveys"
<label for="usageSurveys">Enable notifications for surveys that help to improve NCP</label> type="checkbox" <?php echo $_['community']['USAGE_SURVEYS'] === 'yes' ? ' checked="checked"' : ''; ?>"/>
<label for="adminNotifications">Enable notifications for surveys that help to improve NCP</label>
</li> </li>
<li> <li>
<div>Accounts to notify:</div> <div>Accounts to notify:</div>