diff options
Diffstat (limited to 'apps')
29 files changed, 297 insertions, 39 deletions
diff --git a/apps/dav/l10n/cs.js b/apps/dav/l10n/cs.js index 3fc261855a0..2c22a20c2db 100644 --- a/apps/dav/l10n/cs.js +++ b/apps/dav/l10n/cs.js @@ -77,8 +77,11 @@ OC.L10N.register( "Description: %s" : "Popis: %s", "Where: %s" : "Kde: %s", "%1$s via %2$s" : "%1$s prostřednictvím %2$s", + "Cancelled: %1$s" : "Zrušeno: %1$s", "Invitation canceled" : "Pozvánka zrušena", + "Re: %1$s" : "Odp.: %1$s", "Invitation updated" : "Pozvánka aktualizována", + "Invitation: %1$s" : "Pozvánka: %1$s", "Invitation" : "Pozvání", "Title:" : "Název:", "Time:" : "Čas:", diff --git a/apps/dav/l10n/cs.json b/apps/dav/l10n/cs.json index f5ac115990d..af58f56c931 100644 --- a/apps/dav/l10n/cs.json +++ b/apps/dav/l10n/cs.json @@ -75,8 +75,11 @@ "Description: %s" : "Popis: %s", "Where: %s" : "Kde: %s", "%1$s via %2$s" : "%1$s prostřednictvím %2$s", + "Cancelled: %1$s" : "Zrušeno: %1$s", "Invitation canceled" : "Pozvánka zrušena", + "Re: %1$s" : "Odp.: %1$s", "Invitation updated" : "Pozvánka aktualizována", + "Invitation: %1$s" : "Pozvánka: %1$s", "Invitation" : "Pozvání", "Title:" : "Název:", "Time:" : "Čas:", diff --git a/apps/dav/l10n/de_DE.js b/apps/dav/l10n/de_DE.js index e24b3aaf3b2..7f24cc87297 100644 --- a/apps/dav/l10n/de_DE.js +++ b/apps/dav/l10n/de_DE.js @@ -77,8 +77,11 @@ OC.L10N.register( "Description: %s" : "Beschreibung: %s", "Where: %s" : "Ort: %s", "%1$s via %2$s" : "%1$s über %2$s", + "Cancelled: %1$s" : "Abgesagt: %1$s", "Invitation canceled" : "Einladung abgebrochen", + "Re: %1$s" : "Re: %1$s", "Invitation updated" : "Einladung aktualisiert", + "Invitation: %1$s" : "Einladung: %1$s", "Invitation" : "Einladung", "Title:" : "Titel:", "Time:" : "Zeit:", diff --git a/apps/dav/l10n/de_DE.json b/apps/dav/l10n/de_DE.json index 729938d6437..2483c64f5e3 100644 --- a/apps/dav/l10n/de_DE.json +++ b/apps/dav/l10n/de_DE.json @@ -75,8 +75,11 @@ "Description: %s" : "Beschreibung: %s", "Where: %s" : "Ort: %s", "%1$s via %2$s" : "%1$s über %2$s", + "Cancelled: %1$s" : "Abgesagt: %1$s", "Invitation canceled" : "Einladung abgebrochen", + "Re: %1$s" : "Re: %1$s", "Invitation updated" : "Einladung aktualisiert", + "Invitation: %1$s" : "Einladung: %1$s", "Invitation" : "Einladung", "Title:" : "Titel:", "Time:" : "Zeit:", diff --git a/apps/dav/l10n/pl.js b/apps/dav/l10n/pl.js index d7fadb386d8..f2926b29767 100644 --- a/apps/dav/l10n/pl.js +++ b/apps/dav/l10n/pl.js @@ -77,8 +77,11 @@ OC.L10N.register( "Description: %s" : "Opis: %s", "Where: %s" : "Gdzie: %s", "%1$s via %2$s" : "%1$s przez %2$s", + "Cancelled: %1$s" : "Anulowane: %1$s", "Invitation canceled" : "Zaproszenie anulowane", + "Re: %1$s" : "Odp: %1$s", "Invitation updated" : "Zaproszenie zaktualizowane", + "Invitation: %1$s" : "Zaproszenie: %1$s", "Invitation" : "Zaproszenie", "Title:" : "Tytuł:", "Time:" : "Czas:", diff --git a/apps/dav/l10n/pl.json b/apps/dav/l10n/pl.json index 448bc2d212e..ef9ea9e8abe 100644 --- a/apps/dav/l10n/pl.json +++ b/apps/dav/l10n/pl.json @@ -75,8 +75,11 @@ "Description: %s" : "Opis: %s", "Where: %s" : "Gdzie: %s", "%1$s via %2$s" : "%1$s przez %2$s", + "Cancelled: %1$s" : "Anulowane: %1$s", "Invitation canceled" : "Zaproszenie anulowane", + "Re: %1$s" : "Odp: %1$s", "Invitation updated" : "Zaproszenie zaktualizowane", + "Invitation: %1$s" : "Zaproszenie: %1$s", "Invitation" : "Zaproszenie", "Title:" : "Tytuł:", "Time:" : "Czas:", diff --git a/apps/dav/l10n/zh_CN.js b/apps/dav/l10n/zh_CN.js index 39b1c800b49..c6d394f2f0f 100644 --- a/apps/dav/l10n/zh_CN.js +++ b/apps/dav/l10n/zh_CN.js @@ -77,8 +77,11 @@ OC.L10N.register( "Description: %s" : "描述:%s", "Where: %s" : "地点:%s", "%1$s via %2$s" : "%1$s 通过 %2$s", + "Cancelled: %1$s" : "已取消:%1$s", "Invitation canceled" : "邀请已取消", + "Re: %1$s" : "回复:%1$s", "Invitation updated" : "邀请已更新", + "Invitation: %1$s" : "邀请:%1$s", "Invitation" : "邀请", "Title:" : "标题:", "Time:" : "时间:", diff --git a/apps/dav/l10n/zh_CN.json b/apps/dav/l10n/zh_CN.json index 91d04bd55b4..14881f507a8 100644 --- a/apps/dav/l10n/zh_CN.json +++ b/apps/dav/l10n/zh_CN.json @@ -75,8 +75,11 @@ "Description: %s" : "描述:%s", "Where: %s" : "地点:%s", "%1$s via %2$s" : "%1$s 通过 %2$s", + "Cancelled: %1$s" : "已取消:%1$s", "Invitation canceled" : "邀请已取消", + "Re: %1$s" : "回复:%1$s", "Invitation updated" : "邀请已更新", + "Invitation: %1$s" : "邀请:%1$s", "Invitation" : "邀请", "Title:" : "标题:", "Time:" : "时间:", diff --git a/apps/dav/l10n/zh_HK.js b/apps/dav/l10n/zh_HK.js index a57554fb497..1df431a21e7 100644 --- a/apps/dav/l10n/zh_HK.js +++ b/apps/dav/l10n/zh_HK.js @@ -77,8 +77,11 @@ OC.L10N.register( "Description: %s" : "描述:%s", "Where: %s" : "地點:%s", "%1$s via %2$s" : "%1$s 由 %2$s", + "Cancelled: %1$s" : "已取消:%1$s", "Invitation canceled" : "邀請被取消了", + "Re: %1$s" : "關於: %1$s", "Invitation updated" : "邀請已更新", + "Invitation: %1$s" : "邀請:%1$s", "Invitation" : "邀請", "Title:" : "標題:", "Time:" : "時間:", diff --git a/apps/dav/l10n/zh_HK.json b/apps/dav/l10n/zh_HK.json index a1c3ef6a91c..72baf354de5 100644 --- a/apps/dav/l10n/zh_HK.json +++ b/apps/dav/l10n/zh_HK.json @@ -75,8 +75,11 @@ "Description: %s" : "描述:%s", "Where: %s" : "地點:%s", "%1$s via %2$s" : "%1$s 由 %2$s", + "Cancelled: %1$s" : "已取消:%1$s", "Invitation canceled" : "邀請被取消了", + "Re: %1$s" : "關於: %1$s", "Invitation updated" : "邀請已更新", + "Invitation: %1$s" : "邀請:%1$s", "Invitation" : "邀請", "Title:" : "標題:", "Time:" : "時間:", diff --git a/apps/dav/l10n/zh_TW.js b/apps/dav/l10n/zh_TW.js index c6610f0352d..c7f9e7c0582 100644 --- a/apps/dav/l10n/zh_TW.js +++ b/apps/dav/l10n/zh_TW.js @@ -77,8 +77,11 @@ OC.L10N.register( "Description: %s" : "描述:%s", "Where: %s" : "地點:%s", "%1$s via %2$s" : "%1$s 由 %2$s", + "Cancelled: %1$s" : "已取消:%1$s", "Invitation canceled" : "邀請已取消", + "Re: %1$s" : "回覆:%1$s", "Invitation updated" : "邀請已更新", + "Invitation: %1$s" : "邀請:%1$s", "Invitation" : "邀請", "Title:" : "標題:", "Time:" : "時間:", diff --git a/apps/dav/l10n/zh_TW.json b/apps/dav/l10n/zh_TW.json index ae976ea60eb..9f4a265a5c1 100644 --- a/apps/dav/l10n/zh_TW.json +++ b/apps/dav/l10n/zh_TW.json @@ -75,8 +75,11 @@ "Description: %s" : "描述:%s", "Where: %s" : "地點:%s", "%1$s via %2$s" : "%1$s 由 %2$s", + "Cancelled: %1$s" : "已取消:%1$s", "Invitation canceled" : "邀請已取消", + "Re: %1$s" : "回覆:%1$s", "Invitation updated" : "邀請已更新", + "Invitation: %1$s" : "邀請:%1$s", "Invitation" : "邀請", "Title:" : "標題:", "Time:" : "時間:", diff --git a/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php b/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php index 13aef7ed227..3dd8a7c81e5 100644 --- a/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php +++ b/apps/dav/lib/CalDAV/WebcalCaching/Plugin.php @@ -40,9 +40,12 @@ class Plugin extends ServerPlugin { * list of regular expressions for calendar user agents, * that do not support subscriptions on their own * + * /^MSFT-WIN-3/ - Windows 10 Calendar * @var string[] */ - public const ENABLE_FOR_CLIENTS = []; + public const ENABLE_FOR_CLIENTS = [ + "/^MSFT-WIN-3/" + ]; /** * @var bool diff --git a/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php b/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php index b848a5d591a..310d266cd57 100644 --- a/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php +++ b/apps/dav/tests/unit/CalDAV/WebcalCaching/PluginTest.php @@ -31,7 +31,7 @@ class PluginTest extends \Test\TestCase { $request = $this->createMock(IRequest::class); $request->expects($this->at(0)) ->method('isUserAgent') - ->with([]) + ->with(Plugin::ENABLE_FOR_CLIENTS) ->willReturn(false); $request->expects($this->at(1)) @@ -48,7 +48,7 @@ class PluginTest extends \Test\TestCase { $request = $this->createMock(IRequest::class); $request->expects($this->at(0)) ->method('isUserAgent') - ->with([]) + ->with(Plugin::ENABLE_FOR_CLIENTS) ->willReturn(false); $request->expects($this->at(1)) diff --git a/apps/encryption/lib/Crypto/Crypt.php b/apps/encryption/lib/Crypto/Crypt.php index a7d7c024cbb..8a6be4d3809 100644 --- a/apps/encryption/lib/Crypto/Crypt.php +++ b/apps/encryption/lib/Crypto/Crypt.php @@ -89,6 +89,9 @@ class Crypt { /** @var IL10N */ private $l; + /** @var string|null */ + private $currentCipher; + /** @var bool */ private $supportLegacy; @@ -248,12 +251,17 @@ class Crypt { } /** - * return Cipher either from config.php or the default cipher defined in + * return cipher either from config.php or the default cipher defined in * this class * * @return string */ - public function getCipher() { + private function getCachedCipher() { + if (isset($this->currentCipher)) { + return $this->currentCipher; + } + + // Get cipher either from config.php or the default cipher defined in this class $cipher = $this->config->getSystemValue('cipher', self::DEFAULT_CIPHER); if (!isset(self::SUPPORTED_CIPHERS_AND_KEY_SIZE[$cipher])) { $this->logger->warning( @@ -267,7 +275,18 @@ class Crypt { $cipher = self::DEFAULT_CIPHER; } - return $cipher; + // Remember current cipher to avoid frequent lookups + $this->currentCipher = $cipher; + return $this->currentCipher; + } + + /** + * return current encryption cipher + * + * @return string + */ + public function getCipher() { + return $this->getCachedCipher(); } /** @@ -577,7 +596,7 @@ class Crypt { throw new GenericEncryptionException('Missing Signature', $this->l->t('Missing Signature')); } - // enforce signature for the new 'CTR' ciphers + // Enforce signature for the new 'CTR' ciphers if (!$skipSignatureCheck && $signaturePosition === false && stripos($cipher, 'ctr') !== false) { throw new GenericEncryptionException('Missing Signature', $this->l->t('Missing Signature')); } diff --git a/apps/files/l10n/hu.js b/apps/files/l10n/hu.js index 6b28fffaa62..9928cf46985 100644 --- a/apps/files/l10n/hu.js +++ b/apps/files/l10n/hu.js @@ -79,6 +79,10 @@ OC.L10N.register( "File name cannot be empty." : "A fájlnév nem lehet semmi.", "\"/\" is not allowed inside a file name." : "„/” nem szerepelhet fájlnévben.", "\"{name}\" is not an allowed filetype" : "\"{name}\" nem engedélyetett fájltípus", + "Storage of {owner} is full, files cannot be updated or synced anymore!" : "A {owner} felhasználó tárolója megtelt, a fájlok nem frissíthetők és szinkronizálhatók többé!", + "Group folder \"{mountPoint}\" is full, files cannot be updated or synced anymore!" : "A csoport mappa \"{mountPoint}\" megtelt, a fájlok nem frissíthetőek vagy szinkronizálhatóak többé!", + "External storage \"{mountPoint}\" is full, files cannot be updated or synced anymore!" : "A külső tároló \"{mountPoint}\" megtelt, a fájlok nem frissíthetőek vagy szinkronizálhatóak többé!", + "Your storage is full, files cannot be updated or synced anymore!" : "A tároló megtelt, a fájlok nem frissíthetőek vagy szinkronizálhatóak többé!", "Storage of {owner} is almost full ({usedSpacePercent}%)." : "A(z) {owner} tárhelye majdnem megtelt ({usedSpacePercent}%).", "Group folder \"{mountPoint}\" is almost full ({usedSpacePercent}%)." : "A(z) \"{mountPoint}\" csoportmappa majdnem megtelt ({usedSpacePercent}%).", "External storage \"{mountPoint}\" is almost full ({usedSpacePercent}%)." : "A(z) „{mountPoint}” külső tárhely majdnem megtelt ({usedSpacePercent}%).", diff --git a/apps/files/l10n/hu.json b/apps/files/l10n/hu.json index 4c11e607329..d0015fb6635 100644 --- a/apps/files/l10n/hu.json +++ b/apps/files/l10n/hu.json @@ -77,6 +77,10 @@ "File name cannot be empty." : "A fájlnév nem lehet semmi.", "\"/\" is not allowed inside a file name." : "„/” nem szerepelhet fájlnévben.", "\"{name}\" is not an allowed filetype" : "\"{name}\" nem engedélyetett fájltípus", + "Storage of {owner} is full, files cannot be updated or synced anymore!" : "A {owner} felhasználó tárolója megtelt, a fájlok nem frissíthetők és szinkronizálhatók többé!", + "Group folder \"{mountPoint}\" is full, files cannot be updated or synced anymore!" : "A csoport mappa \"{mountPoint}\" megtelt, a fájlok nem frissíthetőek vagy szinkronizálhatóak többé!", + "External storage \"{mountPoint}\" is full, files cannot be updated or synced anymore!" : "A külső tároló \"{mountPoint}\" megtelt, a fájlok nem frissíthetőek vagy szinkronizálhatóak többé!", + "Your storage is full, files cannot be updated or synced anymore!" : "A tároló megtelt, a fájlok nem frissíthetőek vagy szinkronizálhatóak többé!", "Storage of {owner} is almost full ({usedSpacePercent}%)." : "A(z) {owner} tárhelye majdnem megtelt ({usedSpacePercent}%).", "Group folder \"{mountPoint}\" is almost full ({usedSpacePercent}%)." : "A(z) \"{mountPoint}\" csoportmappa majdnem megtelt ({usedSpacePercent}%).", "External storage \"{mountPoint}\" is almost full ({usedSpacePercent}%)." : "A(z) „{mountPoint}” külső tárhely majdnem megtelt ({usedSpacePercent}%).", diff --git a/apps/files/l10n/zh_HK.js b/apps/files/l10n/zh_HK.js index 5e66c83a17e..66990490620 100644 --- a/apps/files/l10n/zh_HK.js +++ b/apps/files/l10n/zh_HK.js @@ -40,7 +40,7 @@ OC.L10N.register( "Files" : "檔案", "Details" : "詳細資料", "Select" : "選擇", - "Pending" : "等候中", + "Pending" : "待定的", "Unable to determine date" : "無法確定日期", "This operation is forbidden" : "此操作被禁止", "This directory is unavailable, please check the logs or contact the administrator" : "這個目錄無法存取,請檢查伺服器記錄檔或聯絡管理員", diff --git a/apps/files/l10n/zh_HK.json b/apps/files/l10n/zh_HK.json index 9a0e2bf63fb..28a340752c9 100644 --- a/apps/files/l10n/zh_HK.json +++ b/apps/files/l10n/zh_HK.json @@ -38,7 +38,7 @@ "Files" : "檔案", "Details" : "詳細資料", "Select" : "選擇", - "Pending" : "等候中", + "Pending" : "待定的", "Unable to determine date" : "無法確定日期", "This operation is forbidden" : "此操作被禁止", "This directory is unavailable, please check the logs or contact the administrator" : "這個目錄無法存取,請檢查伺服器記錄檔或聯絡管理員", diff --git a/apps/provisioning_api/appinfo/routes.php b/apps/provisioning_api/appinfo/routes.php index 8cf57487d3a..2f981e0c924 100644 --- a/apps/provisioning_api/appinfo/routes.php +++ b/apps/provisioning_api/appinfo/routes.php @@ -54,6 +54,7 @@ return [ ['root' => '/cloud', 'name' => 'Users#getEditableFields', 'url' => '/user/fields', 'verb' => 'GET'], ['root' => '/cloud', 'name' => 'Users#getEditableFieldsForUser', 'url' => '/user/fields/{userId}', 'verb' => 'GET'], ['root' => '/cloud', 'name' => 'Users#editUser', 'url' => '/users/{userId}', 'verb' => 'PUT'], + ['root' => '/cloud', 'name' => 'Users#editUserMultiValue', 'url' => '/users/{userId}/{collectionName}', 'verb' => 'PUT', 'requirements' => ['collectionName' => '^(?!enable$|disable$)[a-zA-Z0-9_]*$']], ['root' => '/cloud', 'name' => 'Users#wipeUserDevices', 'url' => '/users/{userId}/wipe', 'verb' => 'POST'], ['root' => '/cloud', 'name' => 'Users#deleteUser', 'url' => '/users/{userId}', 'verb' => 'DELETE'], ['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'], diff --git a/apps/provisioning_api/lib/Controller/AUserData.php b/apps/provisioning_api/lib/Controller/AUserData.php index c4fa537c2df..e358d282061 100644 --- a/apps/provisioning_api/lib/Controller/AUserData.php +++ b/apps/provisioning_api/lib/Controller/AUserData.php @@ -150,6 +150,20 @@ abstract class AUserData extends OCSController { if ($includeScopes) { $data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(); } + + $additionalEmails = $additionalEmailScopes = []; + $emailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL); + foreach ($emailCollection->getProperties() as $property) { + $additionalEmails[] = $property->getValue(); + if ($includeScopes) { + $additionalEmailScopes[] = $property->getScope(); + } + } + $data[IAccountManager::COLLECTION_EMAIL] = $additionalEmails; + if ($includeScopes) { + $data[IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX] = $additionalEmailScopes; + } + $data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName(); if ($includeScopes) { $data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope(); diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php index 256077e9ae9..d94e8fed8a8 100644 --- a/apps/provisioning_api/lib/Controller/UsersController.php +++ b/apps/provisioning_api/lib/Controller/UsersController.php @@ -52,7 +52,8 @@ use OC\KnownUser\KnownUserService; use OC\User\Backend; use OCA\Settings\Mailer\NewUserMailHelper; use OCP\Accounts\IAccountManager; -use OCP\App\IAppManager; +use OCP\Accounts\IAccountProperty; +use OCP\Accounts\PropertyDoesNotExistException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSException; @@ -75,8 +76,6 @@ use Psr\Log\LoggerInterface; class UsersController extends AUserData { - /** @var IAppManager */ - private $appManager; /** @var IURLGenerator */ protected $urlGenerator; /** @var LoggerInterface */ @@ -98,7 +97,6 @@ class UsersController extends AUserData { IRequest $request, IUserManager $userManager, IConfig $config, - IAppManager $appManager, IGroupManager $groupManager, IUserSession $userSession, IAccountManager $accountManager, @@ -119,7 +117,6 @@ class UsersController extends AUserData { $accountManager, $l10nFactory); - $this->appManager = $appManager; $this->urlGenerator = $urlGenerator; $this->logger = $logger; $this->l10nFactory = $l10nFactory; @@ -592,6 +589,7 @@ class UsersController extends AUserData { $permittedFields[] = IAccountManager::PROPERTY_EMAIL; } + $permittedFields[] = IAccountManager::COLLECTION_EMAIL; $permittedFields[] = IAccountManager::PROPERTY_PHONE; $permittedFields[] = IAccountManager::PROPERTY_ADDRESS; $permittedFields[] = IAccountManager::PROPERTY_WEBSITE; @@ -605,6 +603,92 @@ class UsersController extends AUserData { * @NoSubAdminRequired * @PasswordConfirmationRequired * + * @throws OCSException + */ + public function editUserMultiValue( + string $userId, + string $collectionName, + string $key, + string $value + ): DataResponse { + $currentLoggedInUser = $this->userSession->getUser(); + if ($currentLoggedInUser === null) { + throw new OCSException('', OCSController::RESPOND_UNAUTHORISED); + } + + $targetUser = $this->userManager->get($userId); + if ($targetUser === null) { + throw new OCSException('', OCSController::RESPOND_NOT_FOUND); + } + + $permittedFields = []; + if ($targetUser->getUID() === $currentLoggedInUser->getUID()) { + // Editing self (display, email) + $permittedFields[] = IAccountManager::COLLECTION_EMAIL; + $permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX; + } else { + // Check if admin / subadmin + $subAdminManager = $this->groupManager->getSubAdmin(); + if ($this->groupManager->isAdmin($currentLoggedInUser->getUID()) + || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) { + // They have permissions over the user + + $permittedFields[] = IAccountManager::COLLECTION_EMAIL; + } else { + // No rights + throw new OCSException('', OCSController::RESPOND_NOT_FOUND); + } + } + + // Check if permitted to edit this field + if (!in_array($collectionName, $permittedFields)) { + throw new OCSException('', 103); + } + + switch ($collectionName) { + case IAccountManager::COLLECTION_EMAIL: + $userAccount = $this->accountManager->getAccount($targetUser); + $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL); + $mailCollection->removePropertyByValue($key); + if ($value !== '') { + $mailCollection->addPropertyWithDefaults($value); + } + $this->accountManager->updateAccount($userAccount); + break; + + case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX: + $userAccount = $this->accountManager->getAccount($targetUser); + $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL); + $targetProperty = null; + foreach ($mailCollection->getProperties() as $property) { + if ($property->getValue() === $key) { + $targetProperty = $property; + break; + } + } + if ($targetProperty instanceof IAccountProperty) { + try { + $targetProperty->setScope($value); + $this->accountManager->updateAccount($userAccount); + } catch (\InvalidArgumentException $e) { + throw new OCSException('', 102); + } + } else { + throw new OCSException('', 102); + } + break; + + default: + throw new OCSException('', 103); + } + return new DataResponse(); + } + + /** + * @NoAdminRequired + * @NoSubAdminRequired + * @PasswordConfirmationRequired + * * edit users * * @param string $userId @@ -636,6 +720,8 @@ class UsersController extends AUserData { $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX; $permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX; + $permittedFields[] = IAccountManager::COLLECTION_EMAIL; + $permittedFields[] = 'password'; if ($this->config->getSystemValue('force_language', false) === false || $this->groupManager->isAdmin($currentLoggedInUser->getUID())) { @@ -674,6 +760,7 @@ class UsersController extends AUserData { $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME; } $permittedFields[] = IAccountManager::PROPERTY_EMAIL; + $permittedFields[] = IAccountManager::COLLECTION_EMAIL; $permittedFields[] = 'password'; $permittedFields[] = 'language'; $permittedFields[] = 'locale'; @@ -746,24 +833,42 @@ class UsersController extends AUserData { throw new OCSException('', 102); } break; + case IAccountManager::COLLECTION_EMAIL: + if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getEMailAddress()) { + $userAccount = $this->accountManager->getAccount($targetUser); + $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL); + foreach ($mailCollection->getProperties() as $property) { + if ($property->getValue() === $value) { + break; + } + } + $mailCollection->addPropertyWithDefaults($value); + $this->accountManager->updateAccount($userAccount); + } else { + throw new OCSException('', 102); + } + break; case IAccountManager::PROPERTY_PHONE: case IAccountManager::PROPERTY_ADDRESS: case IAccountManager::PROPERTY_WEBSITE: case IAccountManager::PROPERTY_TWITTER: $userAccount = $this->accountManager->getAccount($targetUser); - $userProperty = $userAccount->getProperty($key); - if ($userProperty->getValue() !== $value) { - try { - $userProperty->setValue($value); - $this->accountManager->updateAccount($userAccount); - - if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) { - $this->knownUserService->deleteByContactUserId($targetUser->getUID()); + try { + $userProperty = $userAccount->getProperty($key); + if ($userProperty->getValue() !== $value) { + try { + $userProperty->setValue($value); + if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) { + $this->knownUserService->deleteByContactUserId($targetUser->getUID()); + } + } catch (\InvalidArgumentException $e) { + throw new OCSException('Invalid ' . $e->getMessage(), 102); } - } catch (\InvalidArgumentException $e) { - throw new OCSException('Invalid ' . $e->getMessage(), 102); } + } catch (PropertyDoesNotExistException $e) { + $userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED); } + $this->accountManager->updateAccount($userAccount); break; case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX: case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX: diff --git a/apps/provisioning_api/tests/Controller/UsersControllerTest.php b/apps/provisioning_api/tests/Controller/UsersControllerTest.php index 742335a919a..238bac34307 100644 --- a/apps/provisioning_api/tests/Controller/UsersControllerTest.php +++ b/apps/provisioning_api/tests/Controller/UsersControllerTest.php @@ -50,7 +50,6 @@ use OCA\Settings\Mailer\NewUserMailHelper; use OCP\Accounts\IAccount; use OCP\Accounts\IAccountManager; use OCP\Accounts\IAccountProperty; -use OCP\App\IAppManager; use OCP\AppFramework\Http\DataResponse; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; @@ -77,8 +76,6 @@ class UsersControllerTest extends TestCase { protected $userManager; /** @var IConfig|MockObject */ protected $config; - /** @var IAppManager|MockObject */ - protected $appManager; /** @var Manager|MockObject */ protected $groupManager; /** @var IUserSession|MockObject */ @@ -111,7 +108,6 @@ class UsersControllerTest extends TestCase { $this->userManager = $this->createMock(IUserManager::class); $this->config = $this->createMock(IConfig::class); - $this->appManager = $this->createMock(IAppManager::class); $this->groupManager = $this->createMock(Manager::class); $this->userSession = $this->createMock(IUserSession::class); $this->logger = $this->createMock(LoggerInterface::class); @@ -131,7 +127,6 @@ class UsersControllerTest extends TestCase { $this->request, $this->userManager, $this->config, - $this->appManager, $this->groupManager, $this->userSession, $this->accountManager, @@ -395,7 +390,6 @@ class UsersControllerTest extends TestCase { $this->request, $this->userManager, $this->config, - $this->appManager, $this->groupManager, $this->userSession, $this->accountManager, @@ -1071,7 +1065,8 @@ class UsersControllerTest extends TestCase { 'backendCapabilities' => [ 'setDisplayName' => true, 'setPassword' => true, - ] + ], + 'additional_mail' => [], ]; $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID'])); } @@ -1198,7 +1193,8 @@ class UsersControllerTest extends TestCase { 'backendCapabilities' => [ 'setDisplayName' => true, 'setPassword' => true, - ] + ], + 'additional_mail' => [], ]; $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID'])); } @@ -1363,7 +1359,8 @@ class UsersControllerTest extends TestCase { 'backendCapabilities' => [ 'setDisplayName' => false, 'setPassword' => false, - ] + ], + 'additional_mail' => [], ]; $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID'])); } @@ -3437,7 +3434,6 @@ class UsersControllerTest extends TestCase { $this->request, $this->userManager, $this->config, - $this->appManager, $this->groupManager, $this->userSession, $this->accountManager, @@ -3510,7 +3506,6 @@ class UsersControllerTest extends TestCase { $this->request, $this->userManager, $this->config, - $this->appManager, $this->groupManager, $this->userSession, $this->accountManager, @@ -3848,6 +3843,7 @@ class UsersControllerTest extends TestCase { public function dataGetEditableFields() { return [ [false, ISetDisplayNameBackend::class, [ + IAccountManager::COLLECTION_EMAIL, IAccountManager::PROPERTY_PHONE, IAccountManager::PROPERTY_ADDRESS, IAccountManager::PROPERTY_WEBSITE, @@ -3856,6 +3852,7 @@ class UsersControllerTest extends TestCase { [true, ISetDisplayNameBackend::class, [ IAccountManager::PROPERTY_DISPLAYNAME, IAccountManager::PROPERTY_EMAIL, + IAccountManager::COLLECTION_EMAIL, IAccountManager::PROPERTY_PHONE, IAccountManager::PROPERTY_ADDRESS, IAccountManager::PROPERTY_WEBSITE, @@ -3863,6 +3860,7 @@ class UsersControllerTest extends TestCase { ]], [true, UserInterface::class, [ IAccountManager::PROPERTY_EMAIL, + IAccountManager::COLLECTION_EMAIL, IAccountManager::PROPERTY_PHONE, IAccountManager::PROPERTY_ADDRESS, IAccountManager::PROPERTY_WEBSITE, diff --git a/apps/settings/l10n/fa.js b/apps/settings/l10n/fa.js index 62a82851ce5..8707cff6562 100644 --- a/apps/settings/l10n/fa.js +++ b/apps/settings/l10n/fa.js @@ -203,7 +203,7 @@ OC.L10N.register( "Account deletion" : "حذف حساب کاربری", "Delete {userid}'s account" : "حساب {userid} را حذف کنید", "Welcome mail sent!" : "نامه خوش آمديد ارسال شد", - "Edit User" : "ویرایش کردن کاربر", + "Edit User" : "ویرایش کاربر", "{size} used" : "{size} مورد استفاده", "New user" : "کاربر جدید", "Will be autogenerated" : "به صورت خودکار تولید می شود", diff --git a/apps/settings/l10n/fa.json b/apps/settings/l10n/fa.json index cbcc894cbfc..2e7ec8b136b 100644 --- a/apps/settings/l10n/fa.json +++ b/apps/settings/l10n/fa.json @@ -201,7 +201,7 @@ "Account deletion" : "حذف حساب کاربری", "Delete {userid}'s account" : "حساب {userid} را حذف کنید", "Welcome mail sent!" : "نامه خوش آمديد ارسال شد", - "Edit User" : "ویرایش کردن کاربر", + "Edit User" : "ویرایش کاربر", "{size} used" : "{size} مورد استفاده", "New user" : "کاربر جدید", "Will be autogenerated" : "به صورت خودکار تولید می شود", diff --git a/apps/settings/l10n/zh_HK.js b/apps/settings/l10n/zh_HK.js index 837fc0e2e72..25e57c40bc5 100644 --- a/apps/settings/l10n/zh_HK.js +++ b/apps/settings/l10n/zh_HK.js @@ -273,7 +273,7 @@ OC.L10N.register( "App bundles" : "應用程式套裝", "Featured apps" : "精選應用程式", "{license}-licensed" : "以 {license} 授權", - "Details" : "詳細資料", + "Details" : "細節", "Changelog" : "變更紀錄", "by {author}\n{license}" : "作者為 {author}\n{license}", "Enter group name" : "輸入群組名稱", diff --git a/apps/settings/l10n/zh_HK.json b/apps/settings/l10n/zh_HK.json index 69446c1dcfe..e53bbb25d5b 100644 --- a/apps/settings/l10n/zh_HK.json +++ b/apps/settings/l10n/zh_HK.json @@ -271,7 +271,7 @@ "App bundles" : "應用程式套裝", "Featured apps" : "精選應用程式", "{license}-licensed" : "以 {license} 授權", - "Details" : "詳細資料", + "Details" : "細節", "Changelog" : "變更紀錄", "by {author}\n{license}" : "作者為 {author}\n{license}", "Enter group name" : "輸入群組名稱", diff --git a/apps/user_status/l10n/sc.js b/apps/user_status/l10n/sc.js new file mode 100644 index 00000000000..094ea311bd9 --- /dev/null +++ b/apps/user_status/l10n/sc.js @@ -0,0 +1,38 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Istados reghentes", + "In a meeting" : "In riunione", + "Commuting" : "Biagende", + "Out sick" : "In maladia", + "Vacationing" : "In vacàntzia", + "Working remotely" : "Traballende in remotu", + "User status" : "Istadu de s'utente", + "Clear status message after" : "Lìmpia su messàgiu de istadu a pustis", + "What's your status?" : "Cale est s'istadu tuo?", + "Set status" : "Imposta istadu", + "Online status" : "Istadu in lìnia", + "Status message" : "Messàgiu de istadu", + "Clear status message" : "Lìmpia su messàgiu de istadu", + "Set status message" : "Imposta messàgiu de istadu", + "There was an error saving the status" : "B'at àpidu un'errore sarvende s'istadu", + "There was an error clearing the status" : "B'at àpidu un'errore limpiende s'istadu", + "No recent status changes" : "Perunu càmbiu de istadu reghente", + "Away" : "Ausente", + "Do not disturb" : "No istorbes", + "{status}, {timestamp}" : "{status}, {timestamp}", + "Don't clear" : "Non nche ddu lìmpies", + "Today" : "Oe", + "This week" : "Custa chida", + "Online" : "In lìnia", + "Invisible" : "Invisìbile", + "Offline" : "Fora de lìnia", + "There was an error saving the new status" : "B'at àpidu un'errore sarvende s'istadu nou", + "30 minutes" : "30 minutos", + "1 hour" : "1 ora", + "4 hours" : "4 oras", + "Mute all notifications" : "Istuda totu is notìficas", + "Appear offline" : "Mustra•ti foras de lìnia", + "Clear status after" : "Lìmpia s'istadu a pustis" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/sc.json b/apps/user_status/l10n/sc.json new file mode 100644 index 00000000000..79d695addfa --- /dev/null +++ b/apps/user_status/l10n/sc.json @@ -0,0 +1,36 @@ +{ "translations": { + "Recent statuses" : "Istados reghentes", + "In a meeting" : "In riunione", + "Commuting" : "Biagende", + "Out sick" : "In maladia", + "Vacationing" : "In vacàntzia", + "Working remotely" : "Traballende in remotu", + "User status" : "Istadu de s'utente", + "Clear status message after" : "Lìmpia su messàgiu de istadu a pustis", + "What's your status?" : "Cale est s'istadu tuo?", + "Set status" : "Imposta istadu", + "Online status" : "Istadu in lìnia", + "Status message" : "Messàgiu de istadu", + "Clear status message" : "Lìmpia su messàgiu de istadu", + "Set status message" : "Imposta messàgiu de istadu", + "There was an error saving the status" : "B'at àpidu un'errore sarvende s'istadu", + "There was an error clearing the status" : "B'at àpidu un'errore limpiende s'istadu", + "No recent status changes" : "Perunu càmbiu de istadu reghente", + "Away" : "Ausente", + "Do not disturb" : "No istorbes", + "{status}, {timestamp}" : "{status}, {timestamp}", + "Don't clear" : "Non nche ddu lìmpies", + "Today" : "Oe", + "This week" : "Custa chida", + "Online" : "In lìnia", + "Invisible" : "Invisìbile", + "Offline" : "Fora de lìnia", + "There was an error saving the new status" : "B'at àpidu un'errore sarvende s'istadu nou", + "30 minutes" : "30 minutos", + "1 hour" : "1 ora", + "4 hours" : "4 oras", + "Mute all notifications" : "Istuda totu is notìficas", + "Appear offline" : "Mustra•ti foras de lìnia", + "Clear status after" : "Lìmpia s'istadu a pustis" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +}
\ No newline at end of file |