aboutsummaryrefslogtreecommitdiffstats
path: root/apps/settings/lib/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'apps/settings/lib/Controller')
-rw-r--r--apps/settings/lib/Controller/AISettingsController.php13
-rw-r--r--apps/settings/lib/Controller/AdminSettingsController.php1
-rw-r--r--apps/settings/lib/Controller/AppSettingsController.php68
-rw-r--r--apps/settings/lib/Controller/AuthorizedGroupController.php2
-rw-r--r--apps/settings/lib/Controller/ChangePasswordController.php7
-rw-r--r--apps/settings/lib/Controller/CommonSettingsTrait.php9
-rw-r--r--apps/settings/lib/Controller/DeclarativeSettingsController.php40
-rw-r--r--apps/settings/lib/Controller/LogSettingsController.php20
-rw-r--r--apps/settings/lib/Controller/MailSettingsController.php46
-rw-r--r--apps/settings/lib/Controller/PersonalSettingsController.php1
-rw-r--r--apps/settings/lib/Controller/UsersController.php64
11 files changed, 198 insertions, 73 deletions
diff --git a/apps/settings/lib/Controller/AISettingsController.php b/apps/settings/lib/Controller/AISettingsController.php
index e08ec616e80..114cbf61514 100644
--- a/apps/settings/lib/Controller/AISettingsController.php
+++ b/apps/settings/lib/Controller/AISettingsController.php
@@ -12,20 +12,15 @@ use OCA\Settings\Settings\Admin\ArtificialIntelligence;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\DataResponse;
-use OCP\IConfig;
+use OCP\IAppConfig;
use OCP\IRequest;
class AISettingsController extends Controller {
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IConfig $config
- */
public function __construct(
$appName,
IRequest $request,
- private IConfig $config,
+ private IAppConfig $appConfig,
) {
parent::__construct($appName, $request);
}
@@ -38,12 +33,12 @@ class AISettingsController extends Controller {
*/
#[AuthorizedAdminSetting(settings: ArtificialIntelligence::class)]
public function update($settings) {
- $keys = ['ai.stt_provider', 'ai.textprocessing_provider_preferences', 'ai.taskprocessing_provider_preferences','ai.taskprocessing_type_preferences', 'ai.translation_provider_preferences', 'ai.text2image_provider'];
+ $keys = ['ai.stt_provider', 'ai.textprocessing_provider_preferences', 'ai.taskprocessing_provider_preferences','ai.taskprocessing_type_preferences', 'ai.translation_provider_preferences', 'ai.text2image_provider', 'ai.taskprocessing_guests'];
foreach ($keys as $key) {
if (!isset($settings[$key])) {
continue;
}
- $this->config->setAppValue('core', $key, json_encode($settings[$key]));
+ $this->appConfig->setValueString('core', $key, json_encode($settings[$key]), lazy: in_array($key, \OC\TaskProcessing\Manager::LAZY_CONFIG_KEYS, true));
}
return new DataResponse();
diff --git a/apps/settings/lib/Controller/AdminSettingsController.php b/apps/settings/lib/Controller/AdminSettingsController.php
index 2b731c5cdde..15e2c392148 100644
--- a/apps/settings/lib/Controller/AdminSettingsController.php
+++ b/apps/settings/lib/Controller/AdminSettingsController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php
index 4d34b7678d7..a85ee8cc20a 100644
--- a/apps/settings/lib/Controller/AppSettingsController.php
+++ b/apps/settings/lib/Controller/AppSettingsController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -15,13 +16,13 @@ use OC\App\AppStore\Version\VersionParser;
use OC\App\DependencyAnalyzer;
use OC\App\Platform;
use OC\Installer;
+use OCA\AppAPI\Service\ExAppsPageService;
use OCP\App\AppPathNotFoundException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
-use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\JSONResponse;
@@ -38,11 +39,14 @@ use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IGroup;
+use OCP\IGroupManager;
use OCP\IL10N;
use OCP\INavigationManager;
use OCP\IRequest;
use OCP\IURLGenerator;
+use OCP\IUserSession;
use OCP\L10N\IFactory;
+use OCP\Security\RateLimiting\ILimiter;
use OCP\Server;
use OCP\Util;
use Psr\Log\LoggerInterface;
@@ -92,9 +96,9 @@ class AppSettingsController extends Controller {
$this->initialState->provideInitialState('appstoreDeveloperDocs', $this->urlGenerator->linkToDocs('developer-manual'));
$this->initialState->provideInitialState('appstoreUpdateCount', count($this->getAppsWithUpdates()));
- if ($this->appManager->isInstalled('app_api')) {
+ if ($this->appManager->isEnabledForAnyone('app_api')) {
try {
- Server::get(\OCA\AppAPI\Service\ExAppsPageService::class)->provideAppApiState($this->initialState);
+ Server::get(ExAppsPageService::class)->provideAppApiState($this->initialState);
} catch (\Psr\Container\NotFoundExceptionInterface|\Psr\Container\ContainerExceptionInterface $e) {
}
}
@@ -126,10 +130,11 @@ class AppSettingsController extends Controller {
* @param string $image
* @throws \Exception
*/
- #[PublicPage]
#[NoCSRFRequired]
- public function getAppDiscoverMedia(string $fileName): Response {
- $etag = $this->discoverFetcher->getETag() ?? date('Y-m');
+ public function getAppDiscoverMedia(string $fileName, ILimiter $limiter, IUserSession $session): Response {
+ $getEtag = $this->discoverFetcher->getETag() ?? date('Y-m');
+ $etag = trim($getEtag, '"');
+
$folder = null;
try {
$folder = $this->appData->getFolder('app-discover-cache');
@@ -156,6 +161,26 @@ class AppSettingsController extends Controller {
$file = reset($file);
// If not found request from Web
if ($file === false) {
+ $user = $session->getUser();
+ // this route is not public thus we can assume a user is logged-in
+ assert($user !== null);
+ // Register a user request to throttle fetching external data
+ // this will prevent using the server for DoS of other systems.
+ $limiter->registerUserRequest(
+ 'settings-discover-media',
+ // allow up to 24 media requests per hour
+ // this should be a sane default when a completely new section is loaded
+ // keep in mind browsers request all files from a source-set
+ 24,
+ 60 * 60,
+ $user,
+ );
+
+ if (!$this->checkCanDownloadMedia($fileName)) {
+ $this->logger->warning('Tried to load media files for app discover section from untrusted source');
+ return new NotFoundResponse(Http::STATUS_BAD_REQUEST);
+ }
+
try {
$client = $this->clientService->newClient();
$fileResponse = $client->get($fileName);
@@ -177,6 +202,31 @@ class AppSettingsController extends Controller {
return $response;
}
+ private function checkCanDownloadMedia(string $filename): bool {
+ $urlInfo = parse_url($filename);
+ if (!isset($urlInfo['host']) || !isset($urlInfo['path'])) {
+ return false;
+ }
+
+ // Always allowed hosts
+ if ($urlInfo['host'] === 'nextcloud.com') {
+ return true;
+ }
+
+ // Hosts that need further verification
+ // Github is only allowed if from our organization
+ $ALLOWED_HOSTS = ['github.com', 'raw.githubusercontent.com'];
+ if (!in_array($urlInfo['host'], $ALLOWED_HOSTS)) {
+ return false;
+ }
+
+ if (str_starts_with($urlInfo['path'], '/nextcloud/') || str_starts_with($urlInfo['path'], '/nextcloud-gmbh/')) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Remove orphaned folders from the image cache that do not match the current etag
* @param ISimpleFolder $folder The folder to clear
@@ -440,7 +490,7 @@ class AppSettingsController extends Controller {
}
$currentVersion = '';
- if ($this->appManager->isInstalled($app['id'])) {
+ if ($this->appManager->isEnabledForAnyone($app['id'])) {
$currentVersion = $this->appManager->getAppVersion($app['id']);
} else {
$currentVersion = $app['releases'][0]['version'];
@@ -519,7 +569,7 @@ class AppSettingsController extends Controller {
// Check if app is already downloaded
/** @var Installer $installer */
- $installer = \OC::$server->get(Installer::class);
+ $installer = Server::get(Installer::class);
$isDownloaded = $installer->isDownloaded($appId);
if (!$isDownloaded) {
@@ -545,7 +595,7 @@ class AppSettingsController extends Controller {
}
private function getGroupList(array $groups) {
- $groupManager = \OC::$server->getGroupManager();
+ $groupManager = Server::get(IGroupManager::class);
$groupsList = [];
foreach ($groups as $group) {
$groupItem = $groupManager->get($group);
diff --git a/apps/settings/lib/Controller/AuthorizedGroupController.php b/apps/settings/lib/Controller/AuthorizedGroupController.php
index ad01b590440..82a1ca4703e 100644
--- a/apps/settings/lib/Controller/AuthorizedGroupController.php
+++ b/apps/settings/lib/Controller/AuthorizedGroupController.php
@@ -57,7 +57,7 @@ class AuthorizedGroupController extends Controller {
$this->authorizedGroupService->create($groupData['gid'], $class);
}
}
-
+
return new DataResponse(['valid' => true]);
}
}
diff --git a/apps/settings/lib/Controller/ChangePasswordController.php b/apps/settings/lib/Controller/ChangePasswordController.php
index 2154a9ab11b..a874a47c16a 100644
--- a/apps/settings/lib/Controller/ChangePasswordController.php
+++ b/apps/settings/lib/Controller/ChangePasswordController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -125,9 +126,9 @@ class ChangePasswordController extends Controller {
$currentUser = $this->userSession->getUser();
$targetUser = $this->userManager->get($username);
- if ($currentUser === null || $targetUser === null ||
- !($this->groupManager->isAdmin($this->userId) ||
- $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
+ if ($currentUser === null || $targetUser === null
+ || !($this->groupManager->isAdmin($this->userId)
+ || $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
) {
return new JSONResponse([
'status' => 'error',
diff --git a/apps/settings/lib/Controller/CommonSettingsTrait.php b/apps/settings/lib/Controller/CommonSettingsTrait.php
index 56760c10f81..75d2b1f2f9e 100644
--- a/apps/settings/lib/Controller/CommonSettingsTrait.php
+++ b/apps/settings/lib/Controller/CommonSettingsTrait.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -144,6 +145,14 @@ trait CommonSettingsTrait {
$this->declarativeSettingsManager->loadSchemas();
$declarativeSettings = $this->declarativeSettingsManager->getFormsWithValues($user, $type, $section);
+ foreach ($declarativeSettings as &$form) {
+ foreach ($form['fields'] as &$field) {
+ if (isset($field['sensitive']) && $field['sensitive'] === true && !empty($field['value'])) {
+ $field['value'] = 'dummySecret';
+ }
+ }
+ }
+
if ($type === 'personal') {
$settings = array_values($this->settingsManager->getPersonalSettings($section));
if ($section === 'theming') {
diff --git a/apps/settings/lib/Controller/DeclarativeSettingsController.php b/apps/settings/lib/Controller/DeclarativeSettingsController.php
index eb9d45839de..4e4bee4043c 100644
--- a/apps/settings/lib/Controller/DeclarativeSettingsController.php
+++ b/apps/settings/lib/Controller/DeclarativeSettingsController.php
@@ -15,6 +15,7 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
use OCA\Settings\ResponseDefinitions;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCSController;
@@ -53,6 +54,45 @@ class DeclarativeSettingsController extends OCSController {
*/
#[NoAdminRequired]
public function setValue(string $app, string $formId, string $fieldId, mixed $value): DataResponse {
+ return $this->saveValue($app, $formId, $fieldId, $value);
+ }
+
+ /**
+ * Sets a declarative settings value.
+ * Password confirmation is required for sensitive values.
+ *
+ * @param string $app ID of the app
+ * @param string $formId ID of the form
+ * @param string $fieldId ID of the field
+ * @param mixed $value Value to be saved
+ * @return DataResponse<Http::STATUS_OK, null, array{}>
+ * @throws NotLoggedInException Not logged in or not an admin user
+ * @throws NotAdminException Not logged in or not an admin user
+ * @throws OCSBadRequestException Invalid arguments to save value
+ *
+ * 200: Value set successfully
+ */
+ #[NoAdminRequired]
+ #[PasswordConfirmationRequired]
+ public function setSensitiveValue(string $app, string $formId, string $fieldId, mixed $value): DataResponse {
+ return $this->saveValue($app, $formId, $fieldId, $value);
+ }
+
+ /**
+ * Sets a declarative settings value.
+ *
+ * @param string $app ID of the app
+ * @param string $formId ID of the form
+ * @param string $fieldId ID of the field
+ * @param mixed $value Value to be saved
+ * @return DataResponse<Http::STATUS_OK, null, array{}>
+ * @throws NotLoggedInException Not logged in or not an admin user
+ * @throws NotAdminException Not logged in or not an admin user
+ * @throws OCSBadRequestException Invalid arguments to save value
+ *
+ * 200: Value set successfully
+ */
+ private function saveValue(string $app, string $formId, string $fieldId, mixed $value): DataResponse {
$user = $this->userSession->getUser();
if ($user === null) {
throw new NotLoggedInException();
diff --git a/apps/settings/lib/Controller/LogSettingsController.php b/apps/settings/lib/Controller/LogSettingsController.php
index aa5ac9b2cc9..90cf4549d2f 100644
--- a/apps/settings/lib/Controller/LogSettingsController.php
+++ b/apps/settings/lib/Controller/LogSettingsController.php
@@ -11,6 +11,7 @@ use OC\Log;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\StreamResponse;
use OCP\IRequest;
@@ -27,22 +28,23 @@ class LogSettingsController extends Controller {
/**
* download logfile
*
- * @psalm-suppress MoreSpecificReturnType The value of Content-Disposition is not relevant
- * @psalm-suppress LessSpecificReturnStatement The value of Content-Disposition is not relevant
- * @return StreamResponse<Http::STATUS_OK, array{Content-Type: 'application/octet-stream', 'Content-Disposition': string}>
+ * @return StreamResponse<Http::STATUS_OK, array{Content-Type: 'application/octet-stream', 'Content-Disposition': 'attachment; filename="nextcloud.log"'}>
*
* 200: Logfile returned
*/
#[NoCSRFRequired]
+ #[OpenAPI(scope: OpenAPI::SCOPE_ADMINISTRATION)]
public function download() {
if (!$this->log instanceof Log) {
throw new \UnexpectedValueException('Log file not available');
}
- $resp = new StreamResponse($this->log->getLogPath());
- $resp->setHeaders([
- 'Content-Type' => 'application/octet-stream',
- 'Content-Disposition' => 'attachment; filename="nextcloud.log"',
- ]);
- return $resp;
+ return new StreamResponse(
+ $this->log->getLogPath(),
+ Http::STATUS_OK,
+ [
+ 'Content-Type' => 'application/octet-stream',
+ 'Content-Disposition' => 'attachment; filename="nextcloud.log"',
+ ],
+ );
}
}
diff --git a/apps/settings/lib/Controller/MailSettingsController.php b/apps/settings/lib/Controller/MailSettingsController.php
index ca037f409b3..f1e3b8032dc 100644
--- a/apps/settings/lib/Controller/MailSettingsController.php
+++ b/apps/settings/lib/Controller/MailSettingsController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -44,34 +45,37 @@ class MailSettingsController extends Controller {
/**
* Sets the email settings
- *
- * @param string $mail_domain
- * @param string $mail_from_address
- * @param string $mail_smtpmode
- * @param string $mail_smtpsecure
- * @param string $mail_smtphost
- * @param int $mail_smtpauth
- * @param string $mail_smtpport
- * @return DataResponse
*/
#[AuthorizedAdminSetting(settings: Overview::class)]
#[PasswordConfirmationRequired]
- public function setMailSettings($mail_domain,
- $mail_from_address,
- $mail_smtpmode,
- $mail_smtpsecure,
- $mail_smtphost,
- $mail_smtpauth,
- $mail_smtpport,
- $mail_sendmailmode) {
- $params = get_defined_vars();
- $configs = [];
- foreach ($params as $key => $value) {
+ public function setMailSettings(
+ string $mail_domain,
+ string $mail_from_address,
+ string $mail_smtpmode,
+ string $mail_smtpsecure,
+ string $mail_smtphost,
+ ?string $mail_smtpauth,
+ string $mail_smtpport,
+ string $mail_sendmailmode,
+ ): DataResponse {
+ $mail_smtpauth = $mail_smtpauth == '1';
+
+ $configs = [
+ 'mail_domain' => $mail_domain,
+ 'mail_from_address' => $mail_from_address,
+ 'mail_smtpmode' => $mail_smtpmode,
+ 'mail_smtpsecure' => $mail_smtpsecure,
+ 'mail_smtphost' => $mail_smtphost,
+ 'mail_smtpauth' => $mail_smtpauth,
+ 'mail_smtpport' => $mail_smtpport,
+ 'mail_sendmailmode' => $mail_sendmailmode,
+ ];
+ foreach ($configs as $key => $value) {
$configs[$key] = empty($value) ? null : $value;
}
// Delete passwords from config in case no auth is specified
- if ($params['mail_smtpauth'] !== 1) {
+ if (!$mail_smtpauth) {
$configs['mail_smtpname'] = null;
$configs['mail_smtppassword'] = null;
}
diff --git a/apps/settings/lib/Controller/PersonalSettingsController.php b/apps/settings/lib/Controller/PersonalSettingsController.php
index 0a87181c7d7..340ca3f93eb 100644
--- a/apps/settings/lib/Controller/PersonalSettingsController.php
+++ b/apps/settings/lib/Controller/PersonalSettingsController.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/apps/settings/lib/Controller/UsersController.php b/apps/settings/lib/Controller/UsersController.php
index 5af16878e8e..8efd3eeb8ca 100644
--- a/apps/settings/lib/Controller/UsersController.php
+++ b/apps/settings/lib/Controller/UsersController.php
@@ -32,6 +32,7 @@ use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
+use OCP\AppFramework\Http\Attribute\UserRateLimit;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\TemplateResponse;
@@ -39,9 +40,12 @@ use OCP\AppFramework\Services\IInitialState;
use OCP\BackgroundJob\IJobList;
use OCP\Encryption\IManager;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Group\ISubAdmin;
use OCP\IConfig;
+use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IL10N;
+use OCP\INavigationManager;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
@@ -52,6 +56,8 @@ use function in_array;
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class UsersController extends Controller {
+ /** Limit for counting users for subadmins, to avoid spending too much time */
+ private const COUNT_LIMIT_FOR_SUBADMINS = 999;
public function __construct(
string $appName,
@@ -83,8 +89,8 @@ class UsersController extends Controller {
*/
#[NoAdminRequired]
#[NoCSRFRequired]
- public function usersListByGroup(): TemplateResponse {
- return $this->usersList();
+ public function usersListByGroup(INavigationManager $navigationManager, ISubAdmin $subAdmin): TemplateResponse {
+ return $this->usersList($navigationManager, $subAdmin);
}
/**
@@ -94,13 +100,13 @@ class UsersController extends Controller {
*/
#[NoAdminRequired]
#[NoCSRFRequired]
- public function usersList(): TemplateResponse {
+ public function usersList(INavigationManager $navigationManager, ISubAdmin $subAdmin): TemplateResponse {
$user = $this->userSession->getUser();
$uid = $user->getUID();
$isAdmin = $this->groupManager->isAdmin($uid);
$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
- \OC::$server->getNavigationManager()->setActiveEntry('core_users');
+ $navigationManager->setActiveEntry('core_users');
/* SORT OPTION: SORT_USERCOUNT or SORT_GROUPNAME */
$sortGroupsBy = MetaData::SORT_USERCOUNT;
@@ -109,8 +115,8 @@ class UsersController extends Controller {
$sortGroupsBy = MetaData::SORT_GROUPNAME;
} else {
if ($this->appManager->isEnabledForUser('user_ldap')) {
- $isLDAPUsed =
- $this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy');
+ $isLDAPUsed
+ = $this->groupManager->isBackendUsed('\OCA\User_LDAP\Group_Proxy');
if ($isLDAPUsed) {
// LDAP user count can be slow, so we sort by group name here
$sortGroupsBy = MetaData::SORT_GROUPNAME;
@@ -129,8 +135,15 @@ class UsersController extends Controller {
$this->userSession
);
- $groupsInfo->setSorting($sortGroupsBy);
- [$adminGroup, $groups] = $groupsInfo->get();
+ $adminGroup = $this->groupManager->get('admin');
+ $adminGroupData = [
+ 'id' => $adminGroup->getGID(),
+ 'name' => $adminGroup->getDisplayName(),
+ 'usercount' => $sortGroupsBy === MetaData::SORT_USERCOUNT ? $adminGroup->count() : 0,
+ 'disabled' => $adminGroup->countDisabled(),
+ 'canAdd' => $adminGroup->canAddUser(),
+ 'canRemove' => $adminGroup->canRemoveUser(),
+ ];
if (!$isLDAPUsed && $this->appManager->isEnabledForUser('user_ldap')) {
$isLDAPUsed = (bool)array_reduce($this->userManager->getBackends(), function ($ldapFound, $backend) {
@@ -149,20 +162,12 @@ class UsersController extends Controller {
}, 0);
} else {
// User is subadmin !
- // Map group list to ids to retrieve the countDisabledUsersOfGroups
- $userGroups = $this->groupManager->getUserGroups($user);
- $groupsIds = [];
-
- foreach ($groups as $key => $group) {
- // $userCount += (int)$group['usercount'];
- $groupsIds[] = $group['id'];
- }
-
- $userCount += $this->userManager->countUsersOfGroups($groupsInfo->getGroups());
- $disabledUsers = $this->userManager->countDisabledUsersOfGroups($groupsIds);
+ [$userCount,$disabledUsers] = $this->userManager->countUsersAndDisabledUsersOfGroups($groupsInfo->getGroups(), self::COUNT_LIMIT_FOR_SUBADMINS);
}
- $userCount -= $disabledUsers;
+ if ($disabledUsers > 0) {
+ $userCount -= $disabledUsers;
+ }
}
$recentUsersGroup = [
@@ -177,6 +182,14 @@ class UsersController extends Controller {
'usercount' => $disabledUsers
];
+ if (!$isAdmin && !$isDelegatedAdmin) {
+ $subAdminGroups = array_map(
+ fn (IGroup $group) => ['id' => $group->getGID(), 'name' => $group->getDisplayName()],
+ $subAdmin->getSubAdminsGroups($user),
+ );
+ $subAdminGroups = array_values($subAdminGroups);
+ }
+
/* QUOTAS PRESETS */
$quotaPreset = $this->parseQuotaPreset($this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
$allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
@@ -199,7 +212,8 @@ class UsersController extends Controller {
/* FINAL DATA */
$serverData = [];
// groups
- $serverData['groups'] = array_merge_recursive($adminGroup, [$recentUsersGroup, $disabledUsersGroup], $groups);
+ $serverData['systemGroups'] = [$adminGroupData, $recentUsersGroup, $disabledUsersGroup];
+ $serverData['subAdminGroups'] = $subAdminGroups ?? [];
// Various data
$serverData['isAdmin'] = $isAdmin;
$serverData['isDelegatedAdmin'] = $isDelegatedAdmin;
@@ -305,6 +319,8 @@ class UsersController extends Controller {
* @param string|null $addressScope
* @param string|null $twitter
* @param string|null $twitterScope
+ * @param string|null $bluesky
+ * @param string|null $blueskyScope
* @param string|null $fediverse
* @param string|null $fediverseScope
* @param string|null $birthdate
@@ -314,6 +330,7 @@ class UsersController extends Controller {
*/
#[NoAdminRequired]
#[PasswordConfirmationRequired]
+ #[UserRateLimit(limit: 5, period: 60)]
public function setUserSettings(?string $avatarScope = null,
?string $displayname = null,
?string $displaynameScope = null,
@@ -327,6 +344,8 @@ class UsersController extends Controller {
?string $addressScope = null,
?string $twitter = null,
?string $twitterScope = null,
+ ?string $bluesky = null,
+ ?string $blueskyScope = null,
?string $fediverse = null,
?string $fediverseScope = null,
?string $birthdate = null,
@@ -371,6 +390,7 @@ class UsersController extends Controller {
IAccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
IAccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
IAccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope],
+ IAccountManager::PROPERTY_BLUESKY => ['value' => $bluesky, 'scope' => $blueskyScope],
IAccountManager::PROPERTY_FEDIVERSE => ['value' => $fediverse, 'scope' => $fediverseScope],
IAccountManager::PROPERTY_BIRTHDATE => ['value' => $birthdate, 'scope' => $birthdateScope],
IAccountManager::PROPERTY_PRONOUNS => ['value' => $pronouns, 'scope' => $pronounsScope],
@@ -413,6 +433,8 @@ class UsersController extends Controller {
'addressScope' => $userAccount->getProperty(IAccountManager::PROPERTY_ADDRESS)->getScope(),
'twitter' => $userAccount->getProperty(IAccountManager::PROPERTY_TWITTER)->getValue(),
'twitterScope' => $userAccount->getProperty(IAccountManager::PROPERTY_TWITTER)->getScope(),
+ 'bluesky' => $userAccount->getProperty(IAccountManager::PROPERTY_BLUESKY)->getValue(),
+ 'blueskyScope' => $userAccount->getProperty(IAccountManager::PROPERTY_BLUESKY)->getScope(),
'fediverse' => $userAccount->getProperty(IAccountManager::PROPERTY_FEDIVERSE)->getValue(),
'fediverseScope' => $userAccount->getProperty(IAccountManager::PROPERTY_FEDIVERSE)->getScope(),
'birthdate' => $userAccount->getProperty(IAccountManager::PROPERTY_BIRTHDATE)->getValue(),