From 404d26aa4a950e246f11ce421c48faef764fce31 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Sat, 7 May 2022 16:27:20 +0200 Subject: [PATCH 01/23] feature addition: [user_ldap] update user profile from LDAP; WIP work-in-progress; TODO update profile Signed-off-by: Marc Hefter --- apps/user_ldap/js/wizard/wizardTabAdvanced.js | 93 ++++++++++++++++++ apps/user_ldap/lib/Configuration.php | 22 +++++ apps/user_ldap/lib/Connection.php | 7 ++ apps/user_ldap/lib/User/Manager.php | 8 ++ apps/user_ldap/lib/User/User.php | 96 +++++++++++++++++++ 5 files changed, 226 insertions(+) diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index be98072dcb3..26bcd15810e 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -125,6 +125,36 @@ OCA = OCA || {}; $element: $('#ldap_ext_storage_home_attribute'), setMethod: 'setExternalStorageHomeAttribute' }, + + //User Profile Attributes + ldap_attr_phone: { + $element: $('#ldap_attr_phone'), + setMethod: 'setPhoneAttribute' + }, + ldap_attr_website: { + $element: $('#ldap_attr_website'), + setMethod: 'setWebsiteAttribute' + }, + ldap_attr_address: { + $element: $('#ldap_attr_address'), + setMethod: 'setAddressAttribute' + }, + ldap_attr_organisation: { + $element: $('#ldap_attr_organisation'), + setMethod: 'setOrganisationAttribute' + }, + ldap_attr_role: { + $element: $('#ldap_attr_role'), + setMethod: 'setRoleAttribute' + }, + ldap_attr_headline: { + $element: $('#ldap_attr_headline'), + setMethod: 'setHeadlineAttribute' + }, + ldap_attr_biography: { + $element: $('#ldap_attr_biography'), + setMethod: 'setBiographyAttribute' + }, }; this.setManagedItems(items); }, @@ -366,6 +396,69 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.home_folder_naming_rule.$element, attribute); }, + /** + * sets the attribute for the Nextcloud user profile phone Number + * + * @param {string} attribute + */ + setPhoneAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_phone.$element, attribute); + }, + + /** + * sets the attribute for the Nextcloud user profile website + * + * @param {string} attribute + */ + setWebsiteAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_website.$element, attribute); + }, + + /** + * sets the attribute for the Nextcloud user profile postal address + * + * @param {string} attribute + */ + setAddressAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_address.$element, attribute); + }, + + /** + * sets the attribute for the Nextcloud user profile organisation + * + * @param {string} attribute + */ + setOrganisationAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_organisation.$element, attribute); + }, + + /** + * sets the attribute for the Nextcloud user profile role + * + * @param {string} attribute + */ + setRoleAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_role.$element, attribute); + }, + + /** + * sets the attribute for the Nextcloud user profile headline + * + * @param {string} attribute + */ + setHeadlineAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_headline.$element, attribute); + }, + + /** + * sets the attribute for the Nextcloud user profile biography + * + * @param {string} attribute + */ + setBiographyAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_biography.$element, attribute); + }, + /** * deals with the result of the Test Connection test * diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 59fac50b90b..91780155251 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -10,6 +10,7 @@ * @author Jörn Friedrich Dreyer * @author Lennart Rosam * @author Lukas Reschke + * @author Marc Hefter * @author Morris Jobke * @author Robin McCorkell * @author Roeland Jago Douma @@ -123,6 +124,13 @@ class Configuration { 'ldapExtStorageHomeAttribute' => null, 'ldapMatchingRuleInChainState' => self::LDAP_SERVER_FEATURE_UNKNOWN, 'ldapConnectionTimeout' => 15, + 'ldapAttributePhone' => null, + 'ldapAttributeWebsite' => null, + 'ldapAttributeAddress' => null, + 'ldapAttributeOrganisation' => null, + 'ldapAttributeRole' => null, + 'ldapAttributeHeadline' => null, + 'ldapAttributeBiography' => null, ]; public function __construct(string $configPrefix, bool $autoRead = true) { @@ -469,6 +477,13 @@ class Configuration { 'ldap_ext_storage_home_attribute' => '', 'ldap_matching_rule_in_chain_state' => self::LDAP_SERVER_FEATURE_UNKNOWN, 'ldap_connection_timeout' => 15, + 'ldap_attr_phone' => '', + 'ldap_attr_website' => '', + 'ldap_attr_address' => '', + 'ldap_attr_organisation' => '', + 'ldap_attr_role' => '', + 'ldap_attr_headline' => '', + 'ldap_attr_biography' => '', ]; } @@ -535,6 +550,13 @@ class Configuration { 'ldap_matching_rule_in_chain_state' => 'ldapMatchingRuleInChainState', 'ldapIgnoreNamingRules' => 'ldapIgnoreNamingRules', // sysconfig 'ldap_connection_timeout' => 'ldapConnectionTimeout', + 'ldap_attr_phone' => 'ldapAttributePhone', + 'ldap_attr_website' => 'ldapAttributeWebsite', + 'ldap_attr_address' => 'ldapAttributeAddress', + 'ldap_attr_organisation' => 'ldapAttributeOrganisation', + 'ldap_attr_role' => 'ldapAttributeRole', + 'ldap_attr_headline' => 'ldapAttributeHeadline', + 'ldap_attr_biography' => 'ldapAttributeBiography', ]; return $array; } diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 6700890c8c7..85c8b5ceda3 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -73,6 +73,13 @@ use Psr\Log\LoggerInterface; * @property int hasMemberOfFilterSupport * @property int useMemberOfToDetectMembership * @property string ldapMatchingRuleInChainState + * @property string ldapAttributePhone + * @property string ldapAttributeWebsite + * @property string ldapAttributeAddress + * @property string ldapAttributeOrganisation + * @property string ldapAttributeRole + * @property string ldapAttributeHeadline + * @property string ldapAttributeBiography */ class Connection extends LDAPUtility { /** diff --git a/apps/user_ldap/lib/User/Manager.php b/apps/user_ldap/lib/User/Manager.php index b1915ab57b5..8e0ad9c5df9 100644 --- a/apps/user_ldap/lib/User/Manager.php +++ b/apps/user_ldap/lib/User/Manager.php @@ -6,6 +6,7 @@ * @author Christoph Wurst * @author Joas Schilling * @author Jörn Friedrich Dreyer + * @author Marc Hefter * @author Morris Jobke * @author Roeland Jago Douma * @author Roger Szabo @@ -152,6 +153,13 @@ class Manager { $this->access->getConnection()->ldapUserDisplayName, $this->access->getConnection()->ldapUserDisplayName2, $this->access->getConnection()->ldapExtStorageHomeAttribute, + $this->access->getConnection()->ldapAttributePhone, + $this->access->getConnection()->ldapAttributeWebsite, + $this->access->getConnection()->ldapAttributeAddress, + $this->access->getConnection()->ldapAttributeOrganisation, + $this->access->getConnection()->ldapAttributeRole, + $this->access->getConnection()->ldapAttributeHeadline, + $this->access->getConnection()->ldapAttributeBiography, ]; $homeRule = (string)$this->access->getConnection()->homeFolderNamingRule; diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index edf43494777..81ced78dab9 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -7,6 +7,7 @@ * @author Joas Schilling * @author Jörn Friedrich Dreyer * @author Juan Pablo Villafáñez + * @author Marc Hefter * @author Morris Jobke * @author Philipp Staiger * @author Roger Szabo @@ -35,6 +36,7 @@ use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Exceptions\AttributeNotSet; use OCA\User_LDAP\FilesystemHelper; +use OCP\Accounts\IAccountManager; use OCP\IAvatarManager; use OCP\IConfig; use OCP\ILogger; @@ -108,6 +110,17 @@ class User { */ public const USER_PREFKEY_FIRSTLOGIN = 'firstLoginAccomplished'; + /** + * DB config keys for user profile + */ + public const USER_PREFKEY_PHONE = 'profile_phone'; + public const USER_PREFKEY_WEBSITE = 'profile_website'; + public const USER_PREFKEY_ADDRESS = 'profile_address'; + public const USER_PREFKEY_ORGANISATION = 'profile_organisation'; + public const USER_PREFKEY_ROLE = 'profile_role'; + public const USER_PREFKEY_HEADLINE = 'profile_headline'; + public const USER_PREFKEY_BIOGRAPHY = 'profile_biography'; + /** * @brief constructor, make sure the subclasses call this one! * @param string $username the internal username @@ -231,6 +244,49 @@ class User { } unset($attr); + //User Profile Field - Phone number + $attr = strtolower($this->connection->ldapAttributePhone); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_PHONE, $ldapEntry[$attr][0]); + } + unset($attr); + //User Profile Field - website + $attr = strtolower($this->connection->ldapAttributeWebsite); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_WEBSITE, $ldapEntry[$attr][0]); + } + unset($attr); + //User Profile Field - Address + $attr = strtolower($this->connection->ldapAttributeAddress); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_ADDRESS, $ldapEntry[$attr][0]); + } + unset($attr); + //User Profile Field - organisation + $attr = strtolower($this->connection->ldapAttributeAddress); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_ORGANISATION, $ldapEntry[$attr][0]); + } + unset($attr); + //User Profile Field - role + $attr = strtolower($this->connection->ldapAttributeAddress); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_ROLE, $ldapEntry[$attr][0]); + } + unset($attr); + //User Profile Field - headline + $attr = strtolower($this->connection->ldapAttributeAddress); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_HEADLINE, $ldapEntry[$attr][0]); + } + unset($attr); + //User Profile Field - biography + $attr = strtolower($this->connection->ldapAttributeAddress); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_BIOGRAPHY, $ldapEntry[$attr][0]); + } + unset($attr); + //Avatar /** @var Connection $connection */ $connection = $this->access->getConnection(); @@ -512,6 +568,46 @@ class User { return $quotaValue === 'none' || $quotaValue === 'default' || \OC_Helper::computerFileSize($quotaValue) !== false; } +/* user profile settings and LDAP attributes + * *** + * interface IAccountManager + * public const PROPERTY_PHONE = 'phone'; + * public const PROPERTY_EMAIL = 'email'; + * public const PROPERTY_WEBSITE = 'website'; + * public const PROPERTY_ADDRESS = 'address'; + * public const PROPERTY_TWITTER = 'twitter'; + * public const PROPERTY_ORGANISATION = 'organisation'; + * public const PROPERTY_ROLE = 'role'; + * public const PROPERTY_HEADLINE = 'headline'; + * public const PROPERTY_BIOGRAPHY = 'biography'; + * public const PROPERTY_PROFILE_ENABLED = 'profile_enabled'; + * public function getAccount(IUser $user): IAccount; + * public function updateAccount(IAccount $account): void; + */ + /** + * fetches values from LDAP and stores it as Nextcloud user value + * @param string $valueFromLDAP if known, to save an LDAP read request + * @return null + */ + public function updateProfile(string $property, $valueFromLDAP = null) { + if ($this->wasRefreshed($property)) { + return; + } + if ($valueFromLDAP !== null) { + //$propertyValue = (string)$valueFromLDAP; + $propertyValue = [$valueFromLDAP]; + } + if ($propertyValue && isset($propertyValue[0])) { + $value = $propertyValue[0]; + $this->config->setUserValue($this->getUsername(), 'user_ldap', $property, $value); + // TODO: update user profile data; call \OCP\Accounts\IAccount::setProperty + return $value; + } else { + $this->config->deleteUserValue($this->getUsername(), 'user_ldap', $property); + return ''; + } + } + /** * called by a post_login hook to save the avatar picture * From 7fa3c674de904b140575112f471c5753aa03a89c Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Thu, 12 May 2022 07:46:22 +0200 Subject: [PATCH 02/23] feature addition: [user_ldap] update user profile from LDAP; WIP; fixing some uggly copy-and-paste errors; testing functionality; preparing and editing the documentation Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/js/wizard/wizardTabAdvanced.js | 13 +++++++ apps/user_ldap/lib/Configuration.php | 3 ++ apps/user_ldap/lib/Connection.php | 1 + apps/user_ldap/lib/User/Manager.php | 1 + apps/user_ldap/lib/User/User.php | 39 +++++++++++++++++-- apps/user_ldap/templates/settings.php | 11 ++++++ 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index 26bcd15810e..d2c3b6d125d 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -139,6 +139,10 @@ OCA = OCA || {}; $element: $('#ldap_attr_address'), setMethod: 'setAddressAttribute' }, + ldap_attr_twitter: { + $element: $('#ldap_attr_twitter'), + setMethod: 'setTwitterAttribute' + }, ldap_attr_organisation: { $element: $('#ldap_attr_organisation'), setMethod: 'setOrganisationAttribute' @@ -423,6 +427,15 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.ldap_attr_address.$element, attribute); }, + /** + * sets the attribute for the Nextcloud user profile twitter + * + * @param {string} attribute + */ + setTwitterAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_twitter.$element, attribute); + }, + /** * sets the attribute for the Nextcloud user profile organisation * diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 91780155251..e29bff4b8c5 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -127,6 +127,7 @@ class Configuration { 'ldapAttributePhone' => null, 'ldapAttributeWebsite' => null, 'ldapAttributeAddress' => null, + 'ldapAttributeTwitter' => null, 'ldapAttributeOrganisation' => null, 'ldapAttributeRole' => null, 'ldapAttributeHeadline' => null, @@ -480,6 +481,7 @@ class Configuration { 'ldap_attr_phone' => '', 'ldap_attr_website' => '', 'ldap_attr_address' => '', + 'ldap_attr_twitter' => '', 'ldap_attr_organisation' => '', 'ldap_attr_role' => '', 'ldap_attr_headline' => '', @@ -553,6 +555,7 @@ class Configuration { 'ldap_attr_phone' => 'ldapAttributePhone', 'ldap_attr_website' => 'ldapAttributeWebsite', 'ldap_attr_address' => 'ldapAttributeAddress', + 'ldap_attr_twitter' => 'ldapAttributeTwitter', 'ldap_attr_organisation' => 'ldapAttributeOrganisation', 'ldap_attr_role' => 'ldapAttributeRole', 'ldap_attr_headline' => 'ldapAttributeHeadline', diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 85c8b5ceda3..f899ee381c8 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -76,6 +76,7 @@ use Psr\Log\LoggerInterface; * @property string ldapAttributePhone * @property string ldapAttributeWebsite * @property string ldapAttributeAddress + * @property string ldapAttributeTwitter * @property string ldapAttributeOrganisation * @property string ldapAttributeRole * @property string ldapAttributeHeadline diff --git a/apps/user_ldap/lib/User/Manager.php b/apps/user_ldap/lib/User/Manager.php index 8e0ad9c5df9..8942563a0d5 100644 --- a/apps/user_ldap/lib/User/Manager.php +++ b/apps/user_ldap/lib/User/Manager.php @@ -156,6 +156,7 @@ class Manager { $this->access->getConnection()->ldapAttributePhone, $this->access->getConnection()->ldapAttributeWebsite, $this->access->getConnection()->ldapAttributeAddress, + $this->access->getConnection()->ldapAttributeTwitter, $this->access->getConnection()->ldapAttributeOrganisation, $this->access->getConnection()->ldapAttributeRole, $this->access->getConnection()->ldapAttributeHeadline, diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 81ced78dab9..e9437d61ab3 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -116,6 +116,7 @@ class User { public const USER_PREFKEY_PHONE = 'profile_phone'; public const USER_PREFKEY_WEBSITE = 'profile_website'; public const USER_PREFKEY_ADDRESS = 'profile_address'; + public const USER_PREFKEY_TWITTER = 'profile_twitter'; public const USER_PREFKEY_ORGANISATION = 'profile_organisation'; public const USER_PREFKEY_ROLE = 'profile_role'; public const USER_PREFKEY_HEADLINE = 'profile_headline'; @@ -262,26 +263,32 @@ class User { $this->updateProfile(self::USER_PREFKEY_ADDRESS, $ldapEntry[$attr][0]); } unset($attr); + //User Profile Field - Twitter + $attr = strtolower($this->connection->ldapAttributeTwitter); + if (isset($ldapEntry[$attr])) { + $this->updateProfile(self::USER_PREFKEY_TWITTER, $ldapEntry[$attr][0]); + } + unset($attr); //User Profile Field - organisation - $attr = strtolower($this->connection->ldapAttributeAddress); + $attr = strtolower($this->connection->ldapAttributeOrganisation); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_ORGANISATION, $ldapEntry[$attr][0]); } unset($attr); //User Profile Field - role - $attr = strtolower($this->connection->ldapAttributeAddress); + $attr = strtolower($this->connection->ldapAttributeRole); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_ROLE, $ldapEntry[$attr][0]); } unset($attr); //User Profile Field - headline - $attr = strtolower($this->connection->ldapAttributeAddress); + $attr = strtolower($this->connection->ldapAttributeHeadline); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_HEADLINE, $ldapEntry[$attr][0]); } unset($attr); //User Profile Field - biography - $attr = strtolower($this->connection->ldapAttributeAddress); + $attr = strtolower($this->connection->ldapAttributeBiography); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_BIOGRAPHY, $ldapEntry[$attr][0]); } @@ -590,6 +597,30 @@ class User { * @return null */ public function updateProfile(string $property, $valueFromLDAP = null) { + // check for valid property and set corresponding profile property + $profileProperty = 'INVALID'; + if (self::USER_PREFKEY_PHONE == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_PHONE; + } elseif (self::USER_PREFKEY_WEBSITE == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_WEBSITE; + } elseif (self::USER_PREFKEY_ADDRESS == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_ADDRESS; + } elseif (self::USER_PREFKEY_TWITTER == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_TWITTER; + } elseif (self::USER_PREFKEY_ORGANISATION == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION; + } elseif (self::USER_PREFKEY_ROLE == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_ROLE; + } elseif (self::USER_PREFKEY_HEADLINE == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_HEADLINE; + } elseif (self::USER_PREFKEY_BIOGRAPHY == $property) { + $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY; + } else { + // TODO: throw exception for invalid property specified + return; + } + $this->logger->info('user profile data from LDAP '.$this->dn.' ('.$profileProperty.')', ['app' => 'user_ldap']); + // check if this property was refreshed before if ($this->wasRefreshed($property)) { return; } diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index a28ef55a306..b779cc1f6e5 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -120,6 +120,17 @@ style('user_ldap', 'settings');

t('Leave empty for username (default). Otherwise, specify an LDAP/AD attribute.'));?>

t('$home in an external storage configuration will be replaced with the value of the specified attribute')); ?>

+

t('User Profile Attributes'));?>

+
+

+

+

+

+

+

+

+

+
From 2315c177261a03a2047f9ba3d11dd96da4fef840 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 17 May 2022 12:49:38 +0200 Subject: [PATCH 03/23] feature addition: [user_ldap] update user profile from LDAP Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 42 +++++++++++++++++--------------- lib/private/User/LazyUser.php | 10 ++++++++ lib/private/User/User.php | 41 +++++++++++++++++++++++++++++++ lib/public/IUser.php | 23 +++++++++++++++++ 4 files changed, 96 insertions(+), 20 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index e9437d61ab3..043f3b2d273 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -36,9 +36,12 @@ use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Exceptions\AttributeNotSet; use OCA\User_LDAP\FilesystemHelper; +use OC\Accounts\AccountManager; use OCP\Accounts\IAccountManager; +use OCP\Accounts\PropertyDoesNotExistException; use OCP\IAvatarManager; use OCP\IConfig; +use OCP\IDBConnection; use OCP\ILogger; use OCP\Image; use OCP\IUser; @@ -575,28 +578,12 @@ class User { return $quotaValue === 'none' || $quotaValue === 'default' || \OC_Helper::computerFileSize($quotaValue) !== false; } -/* user profile settings and LDAP attributes - * *** - * interface IAccountManager - * public const PROPERTY_PHONE = 'phone'; - * public const PROPERTY_EMAIL = 'email'; - * public const PROPERTY_WEBSITE = 'website'; - * public const PROPERTY_ADDRESS = 'address'; - * public const PROPERTY_TWITTER = 'twitter'; - * public const PROPERTY_ORGANISATION = 'organisation'; - * public const PROPERTY_ROLE = 'role'; - * public const PROPERTY_HEADLINE = 'headline'; - * public const PROPERTY_BIOGRAPHY = 'biography'; - * public const PROPERTY_PROFILE_ENABLED = 'profile_enabled'; - * public function getAccount(IUser $user): IAccount; - * public function updateAccount(IAccount $account): void; - */ /** * fetches values from LDAP and stores it as Nextcloud user value * @param string $valueFromLDAP if known, to save an LDAP read request * @return null */ - public function updateProfile(string $property, $valueFromLDAP = null) { + private function updateProfile(string $property, $valueFromLDAP) { // check for valid property and set corresponding profile property $profileProperty = 'INVALID'; if (self::USER_PREFKEY_PHONE == $property) { @@ -616,10 +603,9 @@ class User { } elseif (self::USER_PREFKEY_BIOGRAPHY == $property) { $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY; } else { - // TODO: throw exception for invalid property specified + // FIXME: throw exception for invalid property specified return; } - $this->logger->info('user profile data from LDAP '.$this->dn.' ('.$profileProperty.')', ['app' => 'user_ldap']); // check if this property was refreshed before if ($this->wasRefreshed($property)) { return; @@ -628,12 +614,28 @@ class User { //$propertyValue = (string)$valueFromLDAP; $propertyValue = [$valueFromLDAP]; } + $this->logger->debug('user profile data ('.$profileProperty.') from LDAP '.$this->dn.' ='.((string)$valueFromLDAP), ['app' => 'user_ldap']); if ($propertyValue && isset($propertyValue[0])) { $value = $propertyValue[0]; + try { + $user = $this->userManager->get($this->uid); + if (!is_null($user)) { + $currentValue = (string)$user->getProfilePropertyValue($profileProperty); + if ($currentValue !== $value) { + $user->setProfilePropertyValue($profileProperty,$value); + } + // setScope(IAccountManager::SCOPE_FEDERATED); + // setVerified(IAccountManager::VERIFIED); + } + } catch (PropertyDoesNotExistException $e) { + $this->logger->error('property does not exist: '.$profileProperty.' for user '.$userName.'', ['app' => 'user_ldap']); + return; + } + $this->logger->debug('property updated: '.$profileProperty.'='.$propertyValue.' for user '.$userName.'', ['app' => 'user_ldap']); $this->config->setUserValue($this->getUsername(), 'user_ldap', $property, $value); - // TODO: update user profile data; call \OCP\Accounts\IAccount::setProperty return $value; } else { + // FIXME: I decided, to leave profile untouched, if attribute gets removed from LDAP $this->config->deleteUserValue($this->getUsername(), 'user_ldap', $property); return ''; } diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index 096578b8f37..577c937ee51 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -4,6 +4,8 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2022 Robin Appelman * + * @author Marc Hefter + * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -145,4 +147,12 @@ class LazyUser implements IUser { public function setQuota($quota) { $this->getUser()->setQuota($quota); } + + public function getProfilePropertyValue(string $property): ?string { + return $this->getUser()->getProfilePropertyValue($property); + } + + public function setProfilePropertyValue(string $property, $value) { + $this->getUser()->setProfilePropertyValue($property, $value); + } } diff --git a/lib/private/User/User.php b/lib/private/User/User.php index 2d80dbc7adf..d4f7effcf1d 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -12,6 +12,7 @@ * @author Julius Härtl * @author Leon Klingele * @author Lukas Reschke + * @author Marc Hefter * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma @@ -588,4 +589,44 @@ class User implements IUser { $this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]); } } + + /** + * @param string $property name of the AccountProperty + * @return string|null AccountProperty value + * @throws InvalidArgumentException when the property name is invalid or null + */ + public function getProfilePropertyValue($property): ?string { + if ($property === null) { + throw new InvalidArgumentException('Property can not be null.'); + } + // FIXME: check $property if it's one of the IAccountManager::PROPERTY_* public constants + + // FIXME: I need to get the AccountProperty value to return + //return $this->config->getUserValue($this->uid, 'user_ldap', $property, null); + $this->ensureAccountManager(); + $account = $this->accountManager->getAccount($this); + $property = $account->getProperty($property); + return $property->getValue(); + } + + /** + * @param string $property name of the AccountProperty + * @param string $value AccountProperty value + * @return void + * @throws InvalidArgumentException when the property name is invalid or null + */ + public function setProfilePropertyValue($property, $value) { + if ($property === null) { + throw new InvalidArgumentException('Property can not be null.'); + } + // FIXME: check $property if it's one of the IAccountManager::PROPERTY_* public constants + $this->ensureAccountManager(); + $account = $this->accountManager->getAccount($this); + $property = $account->getProperty($property); + $property->setValue($value); + //$property->setScope(IAccountManager::SCOPE_FEDERATED); + //$property->setVerified(IAccountManager::VERIFIED); + $this->accountManager->updateAccount($account); + return; + } } diff --git a/lib/public/IUser.php b/lib/public/IUser.php index 3a7e6ab1f11..fc732b47757 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -5,6 +5,7 @@ * @author Arthur Schiwon * @author John Molakvoæ * @author Lukas Reschke + * @author Marc Hefter * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma @@ -270,4 +271,26 @@ interface IUser { * @since 9.0.0 */ public function setQuota($quota); + + /** + * get users' profile property value. + * + * @param string $property name see IAccountManager::PROPERTY_* + * @return string AccountProperty value + * @throws InvalidArgumentException when the property name is invalid or null + * @since 25.0.0 + */ + public function getProfilePropertyValue(string $property): ?string; + + /** + * set users' profile property value. + * remove property, if null + * + * @param string $property name from IAccountManager::PROPERTY_* + * @param string $value AccountProperty value + * @return void + * @throws InvalidArgumentException when the property name is invalid or null + * @since 25.0.0 + */ + public function setProfilePropertyValue(string $property, $value); } From eee0275dc5b3cfec8f1470bf9efca357e7d3ca68 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 17 May 2022 18:05:37 +0200 Subject: [PATCH 04/23] added user profile scope setting Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/js/wizard/wizardTabAdvanced.js | 13 ++++ apps/user_ldap/lib/Configuration.php | 3 + apps/user_ldap/lib/Connection.php | 1 + apps/user_ldap/lib/User/User.php | 25 ++++--- apps/user_ldap/templates/settings.php | 1 + lib/private/User/LazyUser.php | 12 +++- lib/private/User/User.php | 66 ++++++++++++++++++- lib/public/IUser.php | 27 +++++++- 8 files changed, 130 insertions(+), 18 deletions(-) diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index d2c3b6d125d..031f2bf2a9d 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -159,6 +159,10 @@ OCA = OCA || {}; $element: $('#ldap_attr_biography'), setMethod: 'setBiographyAttribute' }, + ldap_profile_scope: { + $element: $('#ldap_profile_scope'), + setMethod: 'setProfileScope' + }, }; this.setManagedItems(items); }, @@ -472,6 +476,15 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.ldap_attr_biography.$element, attribute); }, + /** + * sets the visibility scope for the Nextcloud user profile properties + * + * @param {string} scope + */ + setProfileScope: function(scope) { + this.setElementValue(this.managedItems.ldap_profile_scope.$element, scope); + }, + /** * deals with the result of the Test Connection test * diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index e29bff4b8c5..2b42dd9992b 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -132,6 +132,7 @@ class Configuration { 'ldapAttributeRole' => null, 'ldapAttributeHeadline' => null, 'ldapAttributeBiography' => null, + 'ldapProfileScope' => null, ]; public function __construct(string $configPrefix, bool $autoRead = true) { @@ -486,6 +487,7 @@ class Configuration { 'ldap_attr_role' => '', 'ldap_attr_headline' => '', 'ldap_attr_biography' => '', + 'ldap_profile_scope' => '', ]; } @@ -560,6 +562,7 @@ class Configuration { 'ldap_attr_role' => 'ldapAttributeRole', 'ldap_attr_headline' => 'ldapAttributeHeadline', 'ldap_attr_biography' => 'ldapAttributeBiography', + 'ldap_profile_scope' => 'ldapProfileScope', ]; return $array; } diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index f899ee381c8..11aaaec13dd 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -81,6 +81,7 @@ use Psr\Log\LoggerInterface; * @property string ldapAttributeRole * @property string ldapAttributeHeadline * @property string ldapAttributeBiography + * @property string ldapProfileScope */ class Connection extends LDAPUtility { /** diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 043f3b2d273..1f044c6ddd6 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -248,52 +248,57 @@ class User { } unset($attr); + //User profile visibility + $profileScope = $this->connection->ldapProfileScope; + if (is_null($profileScope) || '' === $profileScope || 'unset' === $profileScope) { + $profileScope = null; + } //User Profile Field - Phone number $attr = strtolower($this->connection->ldapAttributePhone); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_PHONE, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_PHONE, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - website $attr = strtolower($this->connection->ldapAttributeWebsite); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_WEBSITE, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_WEBSITE, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - Address $attr = strtolower($this->connection->ldapAttributeAddress); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_ADDRESS, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_ADDRESS, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - Twitter $attr = strtolower($this->connection->ldapAttributeTwitter); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_TWITTER, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_TWITTER, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - organisation $attr = strtolower($this->connection->ldapAttributeOrganisation); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_ORGANISATION, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_ORGANISATION, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - role $attr = strtolower($this->connection->ldapAttributeRole); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_ROLE, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_ROLE, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - headline $attr = strtolower($this->connection->ldapAttributeHeadline); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_HEADLINE, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_HEADLINE, $ldapEntry[$attr][0], $profileScope); } unset($attr); //User Profile Field - biography $attr = strtolower($this->connection->ldapAttributeBiography); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_BIOGRAPHY, $ldapEntry[$attr][0]); + $this->updateProfile(self::USER_PREFKEY_BIOGRAPHY, $ldapEntry[$attr][0], $profileScope); } unset($attr); @@ -583,7 +588,7 @@ class User { * @param string $valueFromLDAP if known, to save an LDAP read request * @return null */ - private function updateProfile(string $property, $valueFromLDAP) { + private function updateProfile(string $property, $valueFromLDAP, $scope=null) { // check for valid property and set corresponding profile property $profileProperty = 'INVALID'; if (self::USER_PREFKEY_PHONE == $property) { @@ -622,7 +627,7 @@ class User { if (!is_null($user)) { $currentValue = (string)$user->getProfilePropertyValue($profileProperty); if ($currentValue !== $value) { - $user->setProfilePropertyValue($profileProperty,$value); + $user->setProfileProperty($profileProperty,$value,$scope,null); } // setScope(IAccountManager::SCOPE_FEDERATED); // setVerified(IAccountManager::VERIFIED); diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index b779cc1f6e5..aee48f85ed0 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -130,6 +130,7 @@ style('user_ldap', 'settings');

+

diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index 577c937ee51..0645983979f 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -152,7 +152,15 @@ class LazyUser implements IUser { return $this->getUser()->getProfilePropertyValue($property); } - public function setProfilePropertyValue(string $property, $value) { - $this->getUser()->setProfilePropertyValue($property, $value); + public function getProfilePropertyScope(string $property): ?string { + return $this->getUser()->getProfilePropertyScope($property); + } + + public function getProfilePropertyVerified(string $property): ?string { + return $this->getUser()->getProfilePropertyVerified($property); + } + + public function setProfileProperty(string $property, $value=null, $scope=null, $verified=null) { + $this->getUser()->setProfileProperty($property, $value, $scope, $verified); } } diff --git a/lib/private/User/User.php b/lib/private/User/User.php index d4f7effcf1d..aaff2db8f5a 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -609,13 +609,47 @@ class User implements IUser { return $property->getValue(); } + /** + * @param string $property name of the AccountProperty + * @return string|null AccountProperty scope + * @throws InvalidArgumentException when the property name is invalid or null + */ + public function getProfilePropertyScope($property): ?string { + if ($property === null) { + throw new InvalidArgumentException('Property can not be null.'); + } + $this->ensureAccountManager(); + $account = $this->accountManager->getAccount($this); + // TODO: this should be stored locally, to reduce database overhead + $property = $account->getProperty($property); + return $property->getScope(); + } + + /** + * @param string $property name of the AccountProperty + * @return string|null AccountProperty verified + * @throws InvalidArgumentException when the property name is invalid or null + */ + public function getProfilePropertyVerified($property): ?string { + if ($property === null) { + throw new InvalidArgumentException('Property can not be null.'); + } + $this->ensureAccountManager(); + $account = $this->accountManager->getAccount($this); + // TODO: this should be stored locally, to reduce database overhead + $property = $account->getProperty($property); + return $property->getVerified(); + } + /** * @param string $property name of the AccountProperty * @param string $value AccountProperty value + * @param string $scope AccountProperty scope + * @param string $verified AccountProperty verified * @return void * @throws InvalidArgumentException when the property name is invalid or null */ - public function setProfilePropertyValue($property, $value) { + public function setProfileProperty($property, $value=null, $scope=null, $verified=null) { if ($property === null) { throw new InvalidArgumentException('Property can not be null.'); } @@ -623,9 +657,35 @@ class User implements IUser { $this->ensureAccountManager(); $account = $this->accountManager->getAccount($this); $property = $account->getProperty($property); + if (null !== $value) { + $property->setValue($value); + } + if (null !== $scope) { + // FIXME: should I default to IAccountManager::SCOPE_FEDERATED + $property->setScope($scope); + } + if (null !== $verified) { + // FIXME: should I default to IAccountManager::VERIFIED + $property->setVerified($verified); + } + $this->accountManager->updateAccount($account); + return; + } + + /** + * @param string $property name of the AccountProperty + * @param string $value AccountProperty value + * @return void + * @throws InvalidArgumentException when the property name is invalid or null + */ + public function setProfilePropertyValue($property, $value) { + if ($property === null) { + throw new InvalidArgumentException('Property can not be null.'); + } + $this->ensureAccountManager(); + $account = $this->accountManager->getAccount($this); + $property = $account->getProperty($property); $property->setValue($value); - //$property->setScope(IAccountManager::SCOPE_FEDERATED); - //$property->setVerified(IAccountManager::VERIFIED); $this->accountManager->updateAccount($account); return; } diff --git a/lib/public/IUser.php b/lib/public/IUser.php index fc732b47757..7dc21a28b08 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -283,14 +283,35 @@ interface IUser { public function getProfilePropertyValue(string $property): ?string; /** - * set users' profile property value. - * remove property, if null + * get users' profile property scope. + * + * @param string $property name see IAccountManager::PROPERTY_* + * @return string AccountProperty scope IAccountManager::SCOPE_* + * @throws InvalidArgumentException when the property name is invalid or null + * @since 25.0.0 + */ + public function getProfilePropertyScope(string $property): ?string; + + /** + * get users' profile property verified. + * + * @param string $property name see IAccountManager::PROPERTY_* + * @return string AccountProperty verification status IAccountManager::NOT_VERIFIED/VERIFICATION_IN_PROGRESS/VERIFIED + * @throws InvalidArgumentException when the property name is invalid or null + * @since 25.0.0 + */ + public function getProfilePropertyVerified(string $property): ?string; + + /** + * set users' profile property value,scope,verified. * * @param string $property name from IAccountManager::PROPERTY_* * @param string $value AccountProperty value + * @param string $scope AccountProperty scope + * @param string $verified AccountProperty verified * @return void * @throws InvalidArgumentException when the property name is invalid or null * @since 25.0.0 */ - public function setProfilePropertyValue(string $property, $value); + public function setProfileProperty(string $property, $value=null, $scope=null, $verified=null); } From c7623c7869729fca3b5c01054f69651018151efd Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 20 May 2022 14:31:55 +0200 Subject: [PATCH 05/23] bugfix: changed forgotten userName, to getUsername Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 1f044c6ddd6..dc6be6ba16d 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -633,10 +633,10 @@ class User { // setVerified(IAccountManager::VERIFIED); } } catch (PropertyDoesNotExistException $e) { - $this->logger->error('property does not exist: '.$profileProperty.' for user '.$userName.'', ['app' => 'user_ldap']); + $this->logger->error('property does not exist: '.$profileProperty.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); return; } - $this->logger->debug('property updated: '.$profileProperty.'='.$propertyValue.' for user '.$userName.'', ['app' => 'user_ldap']); + $this->logger->debug('property updated: '.$profileProperty.'='.$propertyValue.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); $this->config->setUserValue($this->getUsername(), 'user_ldap', $property, $value); return $value; } else { From b72fbd58f61b40db40c2f9a61e47ef8985008dc2 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Sat, 21 May 2022 11:04:19 +0200 Subject: [PATCH 06/23] fixed error: Array to string conversion at user_ldap/lib/User/User.php#639 Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index dc6be6ba16d..a3d87c31541 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -636,7 +636,7 @@ class User { $this->logger->error('property does not exist: '.$profileProperty.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); return; } - $this->logger->debug('property updated: '.$profileProperty.'='.$propertyValue.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); + $this->logger->debug('property updated: '.$profileProperty.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); $this->config->setUserValue($this->getUsername(), 'user_ldap', $property, $value); return $value; } else { From 240c57b94b274f157a4b7d38d168e06b48a8fafc Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Sat, 21 May 2022 16:03:42 +0200 Subject: [PATCH 07/23] cleanup: removed unnecessary imports of IAccountManager, AccountManager, IDBConnection Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index a3d87c31541..85cf3bde301 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -36,16 +36,13 @@ use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Exceptions\AttributeNotSet; use OCA\User_LDAP\FilesystemHelper; -use OC\Accounts\AccountManager; -use OCP\Accounts\IAccountManager; -use OCP\Accounts\PropertyDoesNotExistException; use OCP\IAvatarManager; use OCP\IConfig; -use OCP\IDBConnection; use OCP\ILogger; use OCP\Image; use OCP\IUser; use OCP\IUserManager; +use OCP\Accounts\PropertyDoesNotExistException; use OCP\Notification\IManager as INotificationManager; use Psr\Log\LoggerInterface; From 26aa1c3580374024d91184ddf50d1085c00a0288 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 14 Feb 2023 11:56:51 +0100 Subject: [PATCH 08/23] CleanUp: remove unneeded UNSET, to unclutter code Signed-off-by: march42 Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 85cf3bde301..28d43b81f46 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -255,43 +255,36 @@ class User { if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_PHONE, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - website $attr = strtolower($this->connection->ldapAttributeWebsite); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_WEBSITE, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - Address $attr = strtolower($this->connection->ldapAttributeAddress); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_ADDRESS, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - Twitter $attr = strtolower($this->connection->ldapAttributeTwitter); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_TWITTER, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - organisation $attr = strtolower($this->connection->ldapAttributeOrganisation); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_ORGANISATION, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - role $attr = strtolower($this->connection->ldapAttributeRole); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_ROLE, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - headline $attr = strtolower($this->connection->ldapAttributeHeadline); if (isset($ldapEntry[$attr])) { $this->updateProfile(self::USER_PREFKEY_HEADLINE, $ldapEntry[$attr][0], $profileScope); } - unset($attr); //User Profile Field - biography $attr = strtolower($this->connection->ldapAttributeBiography); if (isset($ldapEntry[$attr])) { From 44065c0fea21f554725d81d37cc0133717114119 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 14 Feb 2023 13:15:49 +0100 Subject: [PATCH 09/23] Fix: Parameter $scope has no provided type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 28d43b81f46..c08847b9db8 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -576,9 +576,8 @@ class User { /** * fetches values from LDAP and stores it as Nextcloud user value * @param string $valueFromLDAP if known, to save an LDAP read request - * @return null */ - private function updateProfile(string $property, $valueFromLDAP, $scope=null) { + private function updateProfile(string $property, $valueFromLDAP, ?string $scope=null): void { // check for valid property and set corresponding profile property $profileProperty = 'INVALID'; if (self::USER_PREFKEY_PHONE == $property) { @@ -628,11 +627,11 @@ class User { } $this->logger->debug('property updated: '.$profileProperty.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); $this->config->setUserValue($this->getUsername(), 'user_ldap', $property, $value); - return $value; + return; } else { // FIXME: I decided, to leave profile untouched, if attribute gets removed from LDAP $this->config->deleteUserValue($this->getUsername(), 'user_ldap', $property); - return ''; + return; } } From 2f76b7a3d5b2d5712afb119db4f7af2e3bcf7bfc Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 17 Feb 2023 10:25:08 +0100 Subject: [PATCH 10/23] CleanUp: tidy checking for empty profileScope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index c08847b9db8..cbe3101239e 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -247,7 +247,7 @@ class User { //User profile visibility $profileScope = $this->connection->ldapProfileScope; - if (is_null($profileScope) || '' === $profileScope || 'unset' === $profileScope) { + if (empty($profileScope) || $profileScope === 'unset') { $profileScope = null; } //User Profile Field - Phone number From 651273808f7e40695539a4ac5b205b8aa46ff9ed Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 17 Feb 2023 10:37:31 +0100 Subject: [PATCH 11/23] CleanUp: correct version to 27 and return value specification Co-authored-by: Pytal <24800714+Pytal@users.noreply.github.com> Signed-off-by: Marc Hefter Signed-off-by: Marc Hefter --- lib/private/User/User.php | 6 +++--- lib/public/IUser.php | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/private/User/User.php b/lib/private/User/User.php index aaff2db8f5a..9449705358d 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -592,7 +592,7 @@ class User implements IUser { /** * @param string $property name of the AccountProperty - * @return string|null AccountProperty value + * @return ?string AccountProperty value * @throws InvalidArgumentException when the property name is invalid or null */ public function getProfilePropertyValue($property): ?string { @@ -611,7 +611,7 @@ class User implements IUser { /** * @param string $property name of the AccountProperty - * @return string|null AccountProperty scope + * @return ?string AccountProperty scope * @throws InvalidArgumentException when the property name is invalid or null */ public function getProfilePropertyScope($property): ?string { @@ -627,7 +627,7 @@ class User implements IUser { /** * @param string $property name of the AccountProperty - * @return string|null AccountProperty verified + * @return ?string AccountProperty verified * @throws InvalidArgumentException when the property name is invalid or null */ public function getProfilePropertyVerified($property): ?string { diff --git a/lib/public/IUser.php b/lib/public/IUser.php index 7dc21a28b08..f942e6f036f 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -278,7 +278,7 @@ interface IUser { * @param string $property name see IAccountManager::PROPERTY_* * @return string AccountProperty value * @throws InvalidArgumentException when the property name is invalid or null - * @since 25.0.0 + * @since 27.0.0 */ public function getProfilePropertyValue(string $property): ?string; @@ -288,7 +288,7 @@ interface IUser { * @param string $property name see IAccountManager::PROPERTY_* * @return string AccountProperty scope IAccountManager::SCOPE_* * @throws InvalidArgumentException when the property name is invalid or null - * @since 25.0.0 + * @since 27.0.0 */ public function getProfilePropertyScope(string $property): ?string; @@ -298,7 +298,7 @@ interface IUser { * @param string $property name see IAccountManager::PROPERTY_* * @return string AccountProperty verification status IAccountManager::NOT_VERIFIED/VERIFICATION_IN_PROGRESS/VERIFIED * @throws InvalidArgumentException when the property name is invalid or null - * @since 25.0.0 + * @since 27.0.0 */ public function getProfilePropertyVerified(string $property): ?string; @@ -311,7 +311,7 @@ interface IUser { * @param string $verified AccountProperty verified * @return void * @throws InvalidArgumentException when the property name is invalid or null - * @since 25.0.0 + * @since 27.0.0 */ public function setProfileProperty(string $property, $value=null, $scope=null, $verified=null); } From 30202907516a8adb2bdc63a3d9d822752a0ae512 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 17 Feb 2023 10:50:46 +0100 Subject: [PATCH 12/23] CleanUp: removed redundant condition if block Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index cbe3101239e..f1be9b28cab 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -604,10 +604,7 @@ class User { if ($this->wasRefreshed($property)) { return; } - if ($valueFromLDAP !== null) { - //$propertyValue = (string)$valueFromLDAP; - $propertyValue = [$valueFromLDAP]; - } + $propertyValue = [$valueFromLDAP]; $this->logger->debug('user profile data ('.$profileProperty.') from LDAP '.$this->dn.' ='.((string)$valueFromLDAP), ['app' => 'user_ldap']); if ($propertyValue && isset($propertyValue[0])) { $value = $propertyValue[0]; From 5c4a05cfd68bb0397cb033f7c5d957ed6f9eabd0 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 17 Feb 2023 15:25:17 +0100 Subject: [PATCH 13/23] CleanUp: removed redundant storing profile attributes in user settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index f1be9b28cab..4807280dc40 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -623,11 +623,9 @@ class User { return; } $this->logger->debug('property updated: '.$profileProperty.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); - $this->config->setUserValue($this->getUsername(), 'user_ldap', $property, $value); return; } else { // FIXME: I decided, to leave profile untouched, if attribute gets removed from LDAP - $this->config->deleteUserValue($this->getUsername(), 'user_ldap', $property); return; } } From f812b8757689edf7a3c1f2751bbd106196e9fafb Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Sun, 26 Feb 2023 20:15:01 +0100 Subject: [PATCH 14/23] handling updateProfile with array of values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit using an array to buffer profile updates, like suggested by @come-nc clean some code and remove unneccessary redundancy added the Fediverse profile property Co-Authored-By: Côme Chilliet <91878298+come-nc@users.noreply.github.com> Signed-off-by: Marc Hefter --- apps/user_ldap/js/wizard/wizardTabAdvanced.js | 13 ++ apps/user_ldap/lib/Configuration.php | 3 + apps/user_ldap/lib/Connection.php | 1 + apps/user_ldap/lib/User/Manager.php | 1 + apps/user_ldap/lib/User/User.php | 126 +++++++++--------- apps/user_ldap/templates/settings.php | 1 + 6 files changed, 79 insertions(+), 66 deletions(-) diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index 031f2bf2a9d..170625ce896 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -159,6 +159,10 @@ OCA = OCA || {}; $element: $('#ldap_attr_biography'), setMethod: 'setBiographyAttribute' }, + ldap_attr_fediverse: { + $element: $('#ldap_attr_fediverse'), + setMethod: 'setFediverseAttribute' + }, ldap_profile_scope: { $element: $('#ldap_profile_scope'), setMethod: 'setProfileScope' @@ -476,6 +480,15 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.ldap_attr_biography.$element, attribute); }, + /** + * sets the attribute for the Nextcloud user profile fediverse + * + * @param {string} attribute + */ + setFediverseAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_fediverse.$element, attribute); + }, + /** * sets the visibility scope for the Nextcloud user profile properties * diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 2b42dd9992b..1eb6c7986e5 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -132,6 +132,7 @@ class Configuration { 'ldapAttributeRole' => null, 'ldapAttributeHeadline' => null, 'ldapAttributeBiography' => null, + 'ldapAttributeFediverse' => null, 'ldapProfileScope' => null, ]; @@ -487,6 +488,7 @@ class Configuration { 'ldap_attr_role' => '', 'ldap_attr_headline' => '', 'ldap_attr_biography' => '', + 'ldap_attr_fediverse' => '', 'ldap_profile_scope' => '', ]; } @@ -562,6 +564,7 @@ class Configuration { 'ldap_attr_role' => 'ldapAttributeRole', 'ldap_attr_headline' => 'ldapAttributeHeadline', 'ldap_attr_biography' => 'ldapAttributeBiography', + 'ldap_attr_fediverse' => 'ldapAttributeFediverse', 'ldap_profile_scope' => 'ldapProfileScope', ]; return $array; diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 11aaaec13dd..8bf2904179a 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -81,6 +81,7 @@ use Psr\Log\LoggerInterface; * @property string ldapAttributeRole * @property string ldapAttributeHeadline * @property string ldapAttributeBiography + * @property string ldapAttributeFediverse * @property string ldapProfileScope */ class Connection extends LDAPUtility { diff --git a/apps/user_ldap/lib/User/Manager.php b/apps/user_ldap/lib/User/Manager.php index 8942563a0d5..d356a272f8c 100644 --- a/apps/user_ldap/lib/User/Manager.php +++ b/apps/user_ldap/lib/User/Manager.php @@ -161,6 +161,7 @@ class Manager { $this->access->getConnection()->ldapAttributeRole, $this->access->getConnection()->ldapAttributeHeadline, $this->access->getConnection()->ldapAttributeBiography, + $this->access->getConnection()->ldapAttributeFediverse, ]; $homeRule = (string)$this->access->getConnection()->homeFolderNamingRule; diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 4807280dc40..93f7ff5c332 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -110,18 +110,6 @@ class User { */ public const USER_PREFKEY_FIRSTLOGIN = 'firstLoginAccomplished'; - /** - * DB config keys for user profile - */ - public const USER_PREFKEY_PHONE = 'profile_phone'; - public const USER_PREFKEY_WEBSITE = 'profile_website'; - public const USER_PREFKEY_ADDRESS = 'profile_address'; - public const USER_PREFKEY_TWITTER = 'profile_twitter'; - public const USER_PREFKEY_ORGANISATION = 'profile_organisation'; - public const USER_PREFKEY_ROLE = 'profile_role'; - public const USER_PREFKEY_HEADLINE = 'profile_headline'; - public const USER_PREFKEY_BIOGRAPHY = 'profile_biography'; - /** * @brief constructor, make sure the subclasses call this one! * @param string $username the internal username @@ -245,6 +233,12 @@ class User { } unset($attr); + /** + * Additions to User_LDAP, for writing the User Profile + * + * @var string|null $profileScope the configured scope of visibility + * @var array $profileValues array of the LDAP data + */ //User profile visibility $profileScope = $this->connection->ldapProfileScope; if (empty($profileScope) || $profileScope === 'unset') { @@ -253,43 +247,54 @@ class User { //User Profile Field - Phone number $attr = strtolower($this->connection->ldapAttributePhone); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_PHONE, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_PHONE] = $ldapEntry[$attr][0]; } //User Profile Field - website $attr = strtolower($this->connection->ldapAttributeWebsite); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_WEBSITE, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] = $ldapEntry[$attr][0]; } //User Profile Field - Address $attr = strtolower($this->connection->ldapAttributeAddress); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_ADDRESS, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] = $ldapEntry[$attr][0]; } //User Profile Field - Twitter $attr = strtolower($this->connection->ldapAttributeTwitter); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_TWITTER, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_TWITTER] = $ldapEntry[$attr][0]; } //User Profile Field - organisation $attr = strtolower($this->connection->ldapAttributeOrganisation); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_ORGANISATION, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION] = $ldapEntry[$attr][0]; } //User Profile Field - role $attr = strtolower($this->connection->ldapAttributeRole); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_ROLE, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ROLE] = $ldapEntry[$attr][0]; } //User Profile Field - headline $attr = strtolower($this->connection->ldapAttributeHeadline); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_HEADLINE, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_HEADLINE] = $ldapEntry[$attr][0]; } //User Profile Field - biography $attr = strtolower($this->connection->ldapAttributeBiography); if (isset($ldapEntry[$attr])) { - $this->updateProfile(self::USER_PREFKEY_BIOGRAPHY, $ldapEntry[$attr][0], $profileScope); + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] = $ldapEntry[$attr][0]; + } + //User Profile Field - fediverse + $attr = strtolower($this->connection->ldapAttributeFediverse); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] = $ldapEntry[$attr][0]; + } + // Update user profile + if(0 < count($profileValues)) { + $this->updateProfile($profileValues, $profileScope); + unset($profileValues); } + unset($profileScope); unset($attr); //Avatar @@ -574,59 +579,48 @@ class User { } /** - * fetches values from LDAP and stores it as Nextcloud user value - * @param string $valueFromLDAP if known, to save an LDAP read request + * takes values from LDAP and stores it as Nextcloud user profile value + * + * @param array $profileValues associaive array of property keys and values from LDAP + * @param string|null $profileScope the scope of visibility to set + * @var string $property the array key (property name from AccountManager class) + * @var string $valueFromLDAP the value as read from LDAP + * @var string $propertyValue + * @var string $value + * @var string $currentValue */ - private function updateProfile(string $property, $valueFromLDAP, ?string $scope=null): void { - // check for valid property and set corresponding profile property - $profileProperty = 'INVALID'; - if (self::USER_PREFKEY_PHONE == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_PHONE; - } elseif (self::USER_PREFKEY_WEBSITE == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_WEBSITE; - } elseif (self::USER_PREFKEY_ADDRESS == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_ADDRESS; - } elseif (self::USER_PREFKEY_TWITTER == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_TWITTER; - } elseif (self::USER_PREFKEY_ORGANISATION == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION; - } elseif (self::USER_PREFKEY_ROLE == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_ROLE; - } elseif (self::USER_PREFKEY_HEADLINE == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_HEADLINE; - } elseif (self::USER_PREFKEY_BIOGRAPHY == $property) { - $profileProperty = \OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY; - } else { - // FIXME: throw exception for invalid property specified + private function updateProfile(array $profileValues, ?string $profileScope=null): void { + // check if user profile was refreshed before + if ($this->wasRefreshed('profile')) { return; } - // check if this property was refreshed before - if ($this->wasRefreshed($property)) { + // check if parameter array is empty + if(0 == count($profileValues)) { return; } - $propertyValue = [$valueFromLDAP]; - $this->logger->debug('user profile data ('.$profileProperty.') from LDAP '.$this->dn.' ='.((string)$valueFromLDAP), ['app' => 'user_ldap']); - if ($propertyValue && isset($propertyValue[0])) { - $value = $propertyValue[0]; - try { - $user = $this->userManager->get($this->uid); - if (!is_null($user)) { - $currentValue = (string)$user->getProfilePropertyValue($profileProperty); - if ($currentValue !== $value) { - $user->setProfileProperty($profileProperty,$value,$scope,null); - } - // setScope(IAccountManager::SCOPE_FEDERATED); - // setVerified(IAccountManager::VERIFIED); + // fetch/prepare user + $user = $this->userManager->get($this->uid); + if (is_null($user)) { + return; + } + // loop through the properties and handle them + foreach($profileValues as $property => $valueFromLDAP) { + $this->logger->debug('user profile data ('.$property.') from LDAP '.$this->dn.' ='.((string)$valueFromLDAP), ['app' => 'user_ldap']); + // check and update profile properties + $propertyValue = [$valueFromLDAP]; + if ($propertyValue && isset($propertyValue[0])) { + $value = $propertyValue[0]; + try { + $currentValue = (string)$user->getProfilePropertyValue($property); + if ($currentValue !== $value) { + $user->setProfileProperty($property,$value,$scope,null); + $this->logger->debug('property updated: '.$property.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); + } + } catch (PropertyDoesNotExistException $e) { + $this->logger->error('property does not exist: '.$property.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); + return; } - } catch (PropertyDoesNotExistException $e) { - $this->logger->error('property does not exist: '.$profileProperty.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); - return; } - $this->logger->debug('property updated: '.$profileProperty.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); - return; - } else { - // FIXME: I decided, to leave profile untouched, if attribute gets removed from LDAP - return; } } diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index aee48f85ed0..c0ff2b6a866 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -130,6 +130,7 @@ style('user_ldap', 'settings');

+

From c6408587ed12634e6d5067a385a7766f3306d894 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Mon, 27 Feb 2023 09:43:42 +0100 Subject: [PATCH 15/23] fixing Psalm messages Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 93f7ff5c332..f327ec44e77 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -583,11 +583,6 @@ class User { * * @param array $profileValues associaive array of property keys and values from LDAP * @param string|null $profileScope the scope of visibility to set - * @var string $property the array key (property name from AccountManager class) - * @var string $valueFromLDAP the value as read from LDAP - * @var string $propertyValue - * @var string $value - * @var string $currentValue */ private function updateProfile(array $profileValues, ?string $profileScope=null): void { // check if user profile was refreshed before @@ -604,16 +599,21 @@ class User { return; } // loop through the properties and handle them + /** @var string $property the array key (property name from AccountManager class) */ + /** @var string $valueFromLDAP the value as read from LDAP */ foreach($profileValues as $property => $valueFromLDAP) { - $this->logger->debug('user profile data ('.$property.') from LDAP '.$this->dn.' ='.((string)$valueFromLDAP), ['app' => 'user_ldap']); + $this->logger->debug('user profile data ('.$property.') from LDAP '.$this->dn, ['app' => 'user_ldap']); // check and update profile properties + /** @var string $propertyValue */ $propertyValue = [$valueFromLDAP]; - if ($propertyValue && isset($propertyValue[0])) { + if (isset($propertyValue[0])) { + /** @var string $value */ $value = $propertyValue[0]; try { + /** @var string $currentValue */ $currentValue = (string)$user->getProfilePropertyValue($property); if ($currentValue !== $value) { - $user->setProfileProperty($property,$value,$scope,null); + $user->setProfileProperty($property,$value,$profileScope,null); $this->logger->debug('property updated: '.$property.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); } } catch (PropertyDoesNotExistException $e) { From dd2bd6a925f0fb482a53eac61e46d680bb074c85 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Sun, 5 Mar 2023 12:01:52 +0100 Subject: [PATCH 16/23] refined code, to be independend from OCP\IUser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rework updateProfile in user_ldap/lib/User/User.php some cleanup at processAttributes in user_ldap/lib/User/User.php rearranged Fediverse attribute, to match profile layout Co-authored-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> Signed-off-by: Marc Hefter --- apps/user_ldap/js/wizard/wizardTabAdvanced.js | 26 +++---- apps/user_ldap/lib/Configuration.php | 6 +- apps/user_ldap/lib/Connection.php | 2 +- apps/user_ldap/lib/User/Manager.php | 2 +- apps/user_ldap/lib/User/User.php | 69 +++++++++---------- apps/user_ldap/templates/settings.php | 2 +- 6 files changed, 51 insertions(+), 56 deletions(-) diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index 170625ce896..5b247294473 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -143,6 +143,10 @@ OCA = OCA || {}; $element: $('#ldap_attr_twitter'), setMethod: 'setTwitterAttribute' }, + ldap_attr_fediverse: { + $element: $('#ldap_attr_fediverse'), + setMethod: 'setFediverseAttribute' + }, ldap_attr_organisation: { $element: $('#ldap_attr_organisation'), setMethod: 'setOrganisationAttribute' @@ -159,10 +163,6 @@ OCA = OCA || {}; $element: $('#ldap_attr_biography'), setMethod: 'setBiographyAttribute' }, - ldap_attr_fediverse: { - $element: $('#ldap_attr_fediverse'), - setMethod: 'setFediverseAttribute' - }, ldap_profile_scope: { $element: $('#ldap_profile_scope'), setMethod: 'setProfileScope' @@ -444,6 +444,15 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.ldap_attr_twitter.$element, attribute); }, + /** + * sets the attribute for the Nextcloud user profile fediverse + * + * @param {string} attribute + */ + setFediverseAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_attr_fediverse.$element, attribute); + }, + /** * sets the attribute for the Nextcloud user profile organisation * @@ -480,15 +489,6 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.ldap_attr_biography.$element, attribute); }, - /** - * sets the attribute for the Nextcloud user profile fediverse - * - * @param {string} attribute - */ - setFediverseAttribute: function(attribute) { - this.setElementValue(this.managedItems.ldap_attr_fediverse.$element, attribute); - }, - /** * sets the visibility scope for the Nextcloud user profile properties * diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 1eb6c7986e5..3935da8fa89 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -128,11 +128,11 @@ class Configuration { 'ldapAttributeWebsite' => null, 'ldapAttributeAddress' => null, 'ldapAttributeTwitter' => null, + 'ldapAttributeFediverse' => null, 'ldapAttributeOrganisation' => null, 'ldapAttributeRole' => null, 'ldapAttributeHeadline' => null, 'ldapAttributeBiography' => null, - 'ldapAttributeFediverse' => null, 'ldapProfileScope' => null, ]; @@ -484,11 +484,11 @@ class Configuration { 'ldap_attr_website' => '', 'ldap_attr_address' => '', 'ldap_attr_twitter' => '', + 'ldap_attr_fediverse' => '', 'ldap_attr_organisation' => '', 'ldap_attr_role' => '', 'ldap_attr_headline' => '', 'ldap_attr_biography' => '', - 'ldap_attr_fediverse' => '', 'ldap_profile_scope' => '', ]; } @@ -560,11 +560,11 @@ class Configuration { 'ldap_attr_website' => 'ldapAttributeWebsite', 'ldap_attr_address' => 'ldapAttributeAddress', 'ldap_attr_twitter' => 'ldapAttributeTwitter', + 'ldap_attr_fediverse' => 'ldapAttributeFediverse', 'ldap_attr_organisation' => 'ldapAttributeOrganisation', 'ldap_attr_role' => 'ldapAttributeRole', 'ldap_attr_headline' => 'ldapAttributeHeadline', 'ldap_attr_biography' => 'ldapAttributeBiography', - 'ldap_attr_fediverse' => 'ldapAttributeFediverse', 'ldap_profile_scope' => 'ldapProfileScope', ]; return $array; diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 8bf2904179a..1c365ef2afc 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -77,11 +77,11 @@ use Psr\Log\LoggerInterface; * @property string ldapAttributeWebsite * @property string ldapAttributeAddress * @property string ldapAttributeTwitter + * @property string ldapAttributeFediverse * @property string ldapAttributeOrganisation * @property string ldapAttributeRole * @property string ldapAttributeHeadline * @property string ldapAttributeBiography - * @property string ldapAttributeFediverse * @property string ldapProfileScope */ class Connection extends LDAPUtility { diff --git a/apps/user_ldap/lib/User/Manager.php b/apps/user_ldap/lib/User/Manager.php index d356a272f8c..04c67a537b8 100644 --- a/apps/user_ldap/lib/User/Manager.php +++ b/apps/user_ldap/lib/User/Manager.php @@ -157,11 +157,11 @@ class Manager { $this->access->getConnection()->ldapAttributeWebsite, $this->access->getConnection()->ldapAttributeAddress, $this->access->getConnection()->ldapAttributeTwitter, + $this->access->getConnection()->ldapAttributeFediverse, $this->access->getConnection()->ldapAttributeOrganisation, $this->access->getConnection()->ldapAttributeRole, $this->access->getConnection()->ldapAttributeHeadline, $this->access->getConnection()->ldapAttributeBiography, - $this->access->getConnection()->ldapAttributeFediverse, ]; $homeRule = (string)$this->access->getConnection()->homeFolderNamingRule; diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index f327ec44e77..3dd8f05a07d 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -32,6 +32,8 @@ */ namespace OCA\User_LDAP\User; +use Exception; +use OC\Accounts\AccountManager; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Exceptions\AttributeNotSet; @@ -42,6 +44,7 @@ use OCP\ILogger; use OCP\Image; use OCP\IUser; use OCP\IUserManager; +use OCP\Accounts\IAccountManager; use OCP\Accounts\PropertyDoesNotExistException; use OCP\Notification\IManager as INotificationManager; use Psr\Log\LoggerInterface; @@ -233,17 +236,12 @@ class User { } unset($attr); - /** - * Additions to User_LDAP, for writing the User Profile - * - * @var string|null $profileScope the configured scope of visibility - * @var array $profileValues array of the LDAP data - */ //User profile visibility $profileScope = $this->connection->ldapProfileScope; if (empty($profileScope) || $profileScope === 'unset') { $profileScope = null; } + $profileValues = array(); // empty array, to prevent unneccessary call to updateProfile //User Profile Field - Phone number $attr = strtolower($this->connection->ldapAttributePhone); if (isset($ldapEntry[$attr])) { @@ -264,6 +262,11 @@ class User { if (isset($ldapEntry[$attr])) { $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_TWITTER] = $ldapEntry[$attr][0]; } + //User Profile Field - fediverse + $attr = strtolower($this->connection->ldapAttributeFediverse); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] = $ldapEntry[$attr][0]; + } //User Profile Field - organisation $attr = strtolower($this->connection->ldapAttributeOrganisation); if (isset($ldapEntry[$attr])) { @@ -284,17 +287,10 @@ class User { if (isset($ldapEntry[$attr])) { $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] = $ldapEntry[$attr][0]; } - //User Profile Field - fediverse - $attr = strtolower($this->connection->ldapAttributeFediverse); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] = $ldapEntry[$attr][0]; - } // Update user profile - if(0 < count($profileValues)) { + if(!empty($profileValues)) { $this->updateProfile($profileValues, $profileScope); - unset($profileValues); } - unset($profileScope); unset($attr); //Avatar @@ -589,39 +585,38 @@ class User { if ($this->wasRefreshed('profile')) { return; } - // check if parameter array is empty - if(0 == count($profileValues)) { - return; - } // fetch/prepare user $user = $this->userManager->get($this->uid); if (is_null($user)) { return; } + // prepare AccountManager and Account + $accountManager = \OC::$server->get(IAccountManager::class); + $account = $accountManager->getAccount($user); // get Account + if (is_null($account)) { + return; + } // loop through the properties and handle them - /** @var string $property the array key (property name from AccountManager class) */ - /** @var string $valueFromLDAP the value as read from LDAP */ foreach($profileValues as $property => $valueFromLDAP) { - $this->logger->debug('user profile data ('.$property.') from LDAP '.$this->dn, ['app' => 'user_ldap']); // check and update profile properties - /** @var string $propertyValue */ - $propertyValue = [$valueFromLDAP]; - if (isset($propertyValue[0])) { - /** @var string $value */ - $value = $propertyValue[0]; - try { - /** @var string $currentValue */ - $currentValue = (string)$user->getProfilePropertyValue($property); - if ($currentValue !== $value) { - $user->setProfileProperty($property,$value,$profileScope,null); - $this->logger->debug('property updated: '.$property.'='.$value.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); - } - } catch (PropertyDoesNotExistException $e) { - $this->logger->error('property does not exist: '.$property.' for user '.$this->getUsername().'', ['app' => 'user_ldap']); - return; - } + $value = (is_array($valueFromLDAP) ? $valueFromLDAP[0] : $valueFromLDAP); // take ONLY the first value, if multiple values specified + try { + $accountProperty = $account->getProperty($property); + $currentValue = $accountProperty->getValue(); + $scope = ($profileScope ? $profileScope : ($accountProperty->getScope() ? $accountProperty->getScope() : AccountManager::DEFAULT_SCOPES[$property])); + } + catch (PropertyDoesNotExistException $e) { // thrown at getProperty + $this->logger->error('property does not exist: '.$property.' for uid='.$this->uid.'', ['app' => 'user_ldap', 'exception' => $e]); + $currentValue = ''; + $scope = ($profileScope ? $profileScope : AccountManager::DEFAULT_SCOPES[$property]); + } + $verified = IAccountManager::VERIFIED; // trust the LDAP admin knew what he put there + if ($currentValue !== $value) { + $account->setProperty($property,$value,$scope,$verified); + $this->logger->debug('property updated: '.$property.'='.$value.' for uid='.$this->uid.'', ['app' => 'user_ldap']); } } + $accountManager->updateAccount($account); } /** diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index c0ff2b6a866..805cfce7c23 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -126,11 +126,11 @@ style('user_ldap', 'settings');

+

-

From 0c6d440643414151add23d4bf7eb4cff326f7b98 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 7 Mar 2023 18:21:17 +0100 Subject: [PATCH 17/23] undoing the additions to OC\IUser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removed changes from lib/public/IUser.php removed changes from lib/private/User/LazyUser.php removed changes from lib/private/User/User.php Co-authored-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> Signed-off-by: Marc Hefter --- lib/private/User/LazyUser.php | 18 ------ lib/private/User/User.php | 101 ---------------------------------- lib/public/IUser.php | 44 --------------- 3 files changed, 163 deletions(-) diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php index 0645983979f..096578b8f37 100644 --- a/lib/private/User/LazyUser.php +++ b/lib/private/User/LazyUser.php @@ -4,8 +4,6 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2022 Robin Appelman * - * @author Marc Hefter - * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -147,20 +145,4 @@ class LazyUser implements IUser { public function setQuota($quota) { $this->getUser()->setQuota($quota); } - - public function getProfilePropertyValue(string $property): ?string { - return $this->getUser()->getProfilePropertyValue($property); - } - - public function getProfilePropertyScope(string $property): ?string { - return $this->getUser()->getProfilePropertyScope($property); - } - - public function getProfilePropertyVerified(string $property): ?string { - return $this->getUser()->getProfilePropertyVerified($property); - } - - public function setProfileProperty(string $property, $value=null, $scope=null, $verified=null) { - $this->getUser()->setProfileProperty($property, $value, $scope, $verified); - } } diff --git a/lib/private/User/User.php b/lib/private/User/User.php index 9449705358d..2d80dbc7adf 100644 --- a/lib/private/User/User.php +++ b/lib/private/User/User.php @@ -12,7 +12,6 @@ * @author Julius Härtl * @author Leon Klingele * @author Lukas Reschke - * @author Marc Hefter * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma @@ -589,104 +588,4 @@ class User implements IUser { $this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]); } } - - /** - * @param string $property name of the AccountProperty - * @return ?string AccountProperty value - * @throws InvalidArgumentException when the property name is invalid or null - */ - public function getProfilePropertyValue($property): ?string { - if ($property === null) { - throw new InvalidArgumentException('Property can not be null.'); - } - // FIXME: check $property if it's one of the IAccountManager::PROPERTY_* public constants - - // FIXME: I need to get the AccountProperty value to return - //return $this->config->getUserValue($this->uid, 'user_ldap', $property, null); - $this->ensureAccountManager(); - $account = $this->accountManager->getAccount($this); - $property = $account->getProperty($property); - return $property->getValue(); - } - - /** - * @param string $property name of the AccountProperty - * @return ?string AccountProperty scope - * @throws InvalidArgumentException when the property name is invalid or null - */ - public function getProfilePropertyScope($property): ?string { - if ($property === null) { - throw new InvalidArgumentException('Property can not be null.'); - } - $this->ensureAccountManager(); - $account = $this->accountManager->getAccount($this); - // TODO: this should be stored locally, to reduce database overhead - $property = $account->getProperty($property); - return $property->getScope(); - } - - /** - * @param string $property name of the AccountProperty - * @return ?string AccountProperty verified - * @throws InvalidArgumentException when the property name is invalid or null - */ - public function getProfilePropertyVerified($property): ?string { - if ($property === null) { - throw new InvalidArgumentException('Property can not be null.'); - } - $this->ensureAccountManager(); - $account = $this->accountManager->getAccount($this); - // TODO: this should be stored locally, to reduce database overhead - $property = $account->getProperty($property); - return $property->getVerified(); - } - - /** - * @param string $property name of the AccountProperty - * @param string $value AccountProperty value - * @param string $scope AccountProperty scope - * @param string $verified AccountProperty verified - * @return void - * @throws InvalidArgumentException when the property name is invalid or null - */ - public function setProfileProperty($property, $value=null, $scope=null, $verified=null) { - if ($property === null) { - throw new InvalidArgumentException('Property can not be null.'); - } - // FIXME: check $property if it's one of the IAccountManager::PROPERTY_* public constants - $this->ensureAccountManager(); - $account = $this->accountManager->getAccount($this); - $property = $account->getProperty($property); - if (null !== $value) { - $property->setValue($value); - } - if (null !== $scope) { - // FIXME: should I default to IAccountManager::SCOPE_FEDERATED - $property->setScope($scope); - } - if (null !== $verified) { - // FIXME: should I default to IAccountManager::VERIFIED - $property->setVerified($verified); - } - $this->accountManager->updateAccount($account); - return; - } - - /** - * @param string $property name of the AccountProperty - * @param string $value AccountProperty value - * @return void - * @throws InvalidArgumentException when the property name is invalid or null - */ - public function setProfilePropertyValue($property, $value) { - if ($property === null) { - throw new InvalidArgumentException('Property can not be null.'); - } - $this->ensureAccountManager(); - $account = $this->accountManager->getAccount($this); - $property = $account->getProperty($property); - $property->setValue($value); - $this->accountManager->updateAccount($account); - return; - } } diff --git a/lib/public/IUser.php b/lib/public/IUser.php index f942e6f036f..3a7e6ab1f11 100644 --- a/lib/public/IUser.php +++ b/lib/public/IUser.php @@ -5,7 +5,6 @@ * @author Arthur Schiwon * @author John Molakvoæ * @author Lukas Reschke - * @author Marc Hefter * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma @@ -271,47 +270,4 @@ interface IUser { * @since 9.0.0 */ public function setQuota($quota); - - /** - * get users' profile property value. - * - * @param string $property name see IAccountManager::PROPERTY_* - * @return string AccountProperty value - * @throws InvalidArgumentException when the property name is invalid or null - * @since 27.0.0 - */ - public function getProfilePropertyValue(string $property): ?string; - - /** - * get users' profile property scope. - * - * @param string $property name see IAccountManager::PROPERTY_* - * @return string AccountProperty scope IAccountManager::SCOPE_* - * @throws InvalidArgumentException when the property name is invalid or null - * @since 27.0.0 - */ - public function getProfilePropertyScope(string $property): ?string; - - /** - * get users' profile property verified. - * - * @param string $property name see IAccountManager::PROPERTY_* - * @return string AccountProperty verification status IAccountManager::NOT_VERIFIED/VERIFICATION_IN_PROGRESS/VERIFIED - * @throws InvalidArgumentException when the property name is invalid or null - * @since 27.0.0 - */ - public function getProfilePropertyVerified(string $property): ?string; - - /** - * set users' profile property value,scope,verified. - * - * @param string $property name from IAccountManager::PROPERTY_* - * @param string $value AccountProperty value - * @param string $scope AccountProperty scope - * @param string $verified AccountProperty verified - * @return void - * @throws InvalidArgumentException when the property name is invalid or null - * @since 27.0.0 - */ - public function setProfileProperty(string $property, $value=null, $scope=null, $verified=null); } From 5ea46d81bb5fff84e8676cf5d7a059edb6271bc1 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 10 Mar 2023 10:56:16 +0100 Subject: [PATCH 18/23] nice up the code handling AccountManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit merging defaultScopes from DEFAULT_SCOPES and account_manager.default_property_scope removing unneccessary profileScope setting (using config.php instead) honoring admin choice 'profile.enabled'=>false in config.php moved checking for empty array to updateProfile function corrected some typos and cleaned some comments Co-authored-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> Signed-off-by: Marc Hefter --- apps/user_ldap/js/wizard/wizardTabAdvanced.js | 13 -- apps/user_ldap/lib/Configuration.php | 3 - apps/user_ldap/lib/Connection.php | 1 - apps/user_ldap/lib/User/User.php | 131 +++++++++--------- apps/user_ldap/templates/settings.php | 1 - 5 files changed, 66 insertions(+), 83 deletions(-) diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js index 5b247294473..a438b847401 100644 --- a/apps/user_ldap/js/wizard/wizardTabAdvanced.js +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -163,10 +163,6 @@ OCA = OCA || {}; $element: $('#ldap_attr_biography'), setMethod: 'setBiographyAttribute' }, - ldap_profile_scope: { - $element: $('#ldap_profile_scope'), - setMethod: 'setProfileScope' - }, }; this.setManagedItems(items); }, @@ -489,15 +485,6 @@ OCA = OCA || {}; this.setElementValue(this.managedItems.ldap_attr_biography.$element, attribute); }, - /** - * sets the visibility scope for the Nextcloud user profile properties - * - * @param {string} scope - */ - setProfileScope: function(scope) { - this.setElementValue(this.managedItems.ldap_profile_scope.$element, scope); - }, - /** * deals with the result of the Test Connection test * diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 3935da8fa89..ef64f75a9ef 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -133,7 +133,6 @@ class Configuration { 'ldapAttributeRole' => null, 'ldapAttributeHeadline' => null, 'ldapAttributeBiography' => null, - 'ldapProfileScope' => null, ]; public function __construct(string $configPrefix, bool $autoRead = true) { @@ -489,7 +488,6 @@ class Configuration { 'ldap_attr_role' => '', 'ldap_attr_headline' => '', 'ldap_attr_biography' => '', - 'ldap_profile_scope' => '', ]; } @@ -565,7 +563,6 @@ class Configuration { 'ldap_attr_role' => 'ldapAttributeRole', 'ldap_attr_headline' => 'ldapAttributeHeadline', 'ldap_attr_biography' => 'ldapAttributeBiography', - 'ldap_profile_scope' => 'ldapProfileScope', ]; return $array; } diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 1c365ef2afc..d8d00dd4d27 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -82,7 +82,6 @@ use Psr\Log\LoggerInterface; * @property string ldapAttributeRole * @property string ldapAttributeHeadline * @property string ldapAttributeBiography - * @property string ldapProfileScope */ class Connection extends LDAPUtility { /** diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 3dd8f05a07d..915bcae8289 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -47,6 +47,7 @@ use OCP\IUserManager; use OCP\Accounts\IAccountManager; use OCP\Accounts\PropertyDoesNotExistException; use OCP\Notification\IManager as INotificationManager; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -236,62 +237,58 @@ class User { } unset($attr); - //User profile visibility - $profileScope = $this->connection->ldapProfileScope; - if (empty($profileScope) || $profileScope === 'unset') { - $profileScope = null; - } - $profileValues = array(); // empty array, to prevent unneccessary call to updateProfile - //User Profile Field - Phone number - $attr = strtolower($this->connection->ldapAttributePhone); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_PHONE] = $ldapEntry[$attr][0]; - } - //User Profile Field - website - $attr = strtolower($this->connection->ldapAttributeWebsite); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] = $ldapEntry[$attr][0]; - } - //User Profile Field - Address - $attr = strtolower($this->connection->ldapAttributeAddress); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] = $ldapEntry[$attr][0]; - } - //User Profile Field - Twitter - $attr = strtolower($this->connection->ldapAttributeTwitter); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_TWITTER] = $ldapEntry[$attr][0]; - } - //User Profile Field - fediverse - $attr = strtolower($this->connection->ldapAttributeFediverse); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] = $ldapEntry[$attr][0]; - } - //User Profile Field - organisation - $attr = strtolower($this->connection->ldapAttributeOrganisation); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION] = $ldapEntry[$attr][0]; - } - //User Profile Field - role - $attr = strtolower($this->connection->ldapAttributeRole); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ROLE] = $ldapEntry[$attr][0]; - } - //User Profile Field - headline - $attr = strtolower($this->connection->ldapAttributeHeadline); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_HEADLINE] = $ldapEntry[$attr][0]; - } - //User Profile Field - biography - $attr = strtolower($this->connection->ldapAttributeBiography); - if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] = $ldapEntry[$attr][0]; - } - // Update user profile - if(!empty($profileValues)) { - $this->updateProfile($profileValues, $profileScope); + // honoring profile disabled in config.php + if ($this->config->getSystemValueBool('profile.enabled', true)) { + $profileValues = array(); // empty array, to prevent unneccessary call to updateProfile + //User Profile Field - Phone number + $attr = strtolower($this->connection->ldapAttributePhone); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_PHONE] = $ldapEntry[$attr][0]; + } + //User Profile Field - website + $attr = strtolower($this->connection->ldapAttributeWebsite); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] = $ldapEntry[$attr][0]; + } + //User Profile Field - Address + $attr = strtolower($this->connection->ldapAttributeAddress); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] = $ldapEntry[$attr][0]; + } + //User Profile Field - Twitter + $attr = strtolower($this->connection->ldapAttributeTwitter); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_TWITTER] = $ldapEntry[$attr][0]; + } + //User Profile Field - fediverse + $attr = strtolower($this->connection->ldapAttributeFediverse); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] = $ldapEntry[$attr][0]; + } + //User Profile Field - organisation + $attr = strtolower($this->connection->ldapAttributeOrganisation); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION] = $ldapEntry[$attr][0]; + } + //User Profile Field - role + $attr = strtolower($this->connection->ldapAttributeRole); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ROLE] = $ldapEntry[$attr][0]; + } + //User Profile Field - headline + $attr = strtolower($this->connection->ldapAttributeHeadline); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_HEADLINE] = $ldapEntry[$attr][0]; + } + //User Profile Field - biography + $attr = strtolower($this->connection->ldapAttributeBiography); + if (isset($ldapEntry[$attr])) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] = $ldapEntry[$attr][0]; + } + // Update user profile + $this->updateProfile($profileValues); + unset($attr); } - unset($attr); //Avatar /** @var Connection $connection */ @@ -577,25 +574,29 @@ class User { /** * takes values from LDAP and stores it as Nextcloud user profile value * - * @param array $profileValues associaive array of property keys and values from LDAP - * @param string|null $profileScope the scope of visibility to set + * @param array $profileValues associative array of property keys and values from LDAP */ - private function updateProfile(array $profileValues, ?string $profileScope=null): void { + private function updateProfile(array $profileValues): void { + // check if given array is empty + if (empty($profileValues)) { + return; // okay, nothing to do + } // check if user profile was refreshed before if ($this->wasRefreshed('profile')) { - return; + return; // okay, updated before } // fetch/prepare user $user = $this->userManager->get($this->uid); if (is_null($user)) { - return; + return; // FIXME: I guess userManager::get would never return null here } // prepare AccountManager and Account - $accountManager = \OC::$server->get(IAccountManager::class); + $accountManager = Server::get(IAccountManager::class); $account = $accountManager->getAccount($user); // get Account if (is_null($account)) { - return; + return; // FIXME: I guess getAccount would never return null here } + $defaultScopes = array_merge(AccountManager::DEFAULT_SCOPES, $this->config->getSystemValue('account_manager.default_property_scope', [])); // loop through the properties and handle them foreach($profileValues as $property => $valueFromLDAP) { // check and update profile properties @@ -603,17 +604,17 @@ class User { try { $accountProperty = $account->getProperty($property); $currentValue = $accountProperty->getValue(); - $scope = ($profileScope ? $profileScope : ($accountProperty->getScope() ? $accountProperty->getScope() : AccountManager::DEFAULT_SCOPES[$property])); + $scope = ($accountProperty->getScope() ? $accountProperty->getScope() : $defaultScopes[$property]); } catch (PropertyDoesNotExistException $e) { // thrown at getProperty $this->logger->error('property does not exist: '.$property.' for uid='.$this->uid.'', ['app' => 'user_ldap', 'exception' => $e]); $currentValue = ''; - $scope = ($profileScope ? $profileScope : AccountManager::DEFAULT_SCOPES[$property]); + $scope = $defaultScopes[$property]; } $verified = IAccountManager::VERIFIED; // trust the LDAP admin knew what he put there if ($currentValue !== $value) { $account->setProperty($property,$value,$scope,$verified); - $this->logger->debug('property updated: '.$property.'='.$value.' for uid='.$this->uid.'', ['app' => 'user_ldap']); + $this->logger->debug('update property: '.$property.'='.$value.' for uid='.$this->uid.'', ['app' => 'user_ldap']); } } $accountManager->updateAccount($account); diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 805cfce7c23..916ff84b82a 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -131,7 +131,6 @@ style('user_ldap', 'settings');

-

From 1e7bc93ec8b2c39f60993f42243bb8d7f3af2235 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 21 Mar 2023 22:55:48 +0100 Subject: [PATCH 19/23] handling, formatting of postalAddress attribute syntax replace '$' with ', ' delimiter for address property reformatted some code to 80 column early check and return, if wasRefreshed('profile') removed FIXMEs after digging and double checking Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 63 ++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 915bcae8289..f44ea8f9084 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -237,53 +237,69 @@ class User { } unset($attr); - // honoring profile disabled in config.php - if ($this->config->getSystemValueBool('profile.enabled', true)) { - $profileValues = array(); // empty array, to prevent unneccessary call to updateProfile + // honoring profile disabled in config.php and check if user profile was refreshed + if ($this->config->getSystemValueBool('profile.enabled', true) && + !$this->wasRefreshed('profile')) { + $profileValues = array(); //User Profile Field - Phone number $attr = strtolower($this->connection->ldapAttributePhone); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_PHONE] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_PHONE] + = $ldapEntry[$attr][0]; } //User Profile Field - website $attr = strtolower($this->connection->ldapAttributeWebsite); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] + = $ldapEntry[$attr][0]; } //User Profile Field - Address $attr = strtolower($this->connection->ldapAttributeAddress); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] = $ldapEntry[$attr][0]; + // basic format conversion from postalAddress syntax to comma delimited + if (str_contains($ldapEntry[$attr][0],'$')) { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] + = str_replace('$', ", ", $ldapEntry[$attr][0]); + } else { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] + = $ldapEntry[$attr][0]; + } } //User Profile Field - Twitter $attr = strtolower($this->connection->ldapAttributeTwitter); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_TWITTER] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_TWITTER] + = $ldapEntry[$attr][0]; } //User Profile Field - fediverse $attr = strtolower($this->connection->ldapAttributeFediverse); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_FEDIVERSE] + = $ldapEntry[$attr][0]; } //User Profile Field - organisation $attr = strtolower($this->connection->ldapAttributeOrganisation); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ORGANISATION] + = $ldapEntry[$attr][0]; } //User Profile Field - role $attr = strtolower($this->connection->ldapAttributeRole); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ROLE] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ROLE] + = $ldapEntry[$attr][0]; } //User Profile Field - headline $attr = strtolower($this->connection->ldapAttributeHeadline); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_HEADLINE] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_HEADLINE] + = $ldapEntry[$attr][0]; } //User Profile Field - biography $attr = strtolower($this->connection->ldapAttributeBiography); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] = $ldapEntry[$attr][0]; + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] + = $ldapEntry[$attr][0]; } // Update user profile $this->updateProfile($profileValues); @@ -581,22 +597,17 @@ class User { if (empty($profileValues)) { return; // okay, nothing to do } - // check if user profile was refreshed before - if ($this->wasRefreshed('profile')) { - return; // okay, updated before - } // fetch/prepare user $user = $this->userManager->get($this->uid); if (is_null($user)) { - return; // FIXME: I guess userManager::get would never return null here + $this->logger->error('could not get user for uid='.$this->uid.'', ['app' => 'user_ldap']); + return; } // prepare AccountManager and Account $accountManager = Server::get(IAccountManager::class); $account = $accountManager->getAccount($user); // get Account - if (is_null($account)) { - return; // FIXME: I guess getAccount would never return null here - } - $defaultScopes = array_merge(AccountManager::DEFAULT_SCOPES, $this->config->getSystemValue('account_manager.default_property_scope', [])); + $defaultScopes = array_merge(AccountManager::DEFAULT_SCOPES, + $this->config->getSystemValue('account_manager.default_property_scope', [])); // loop through the properties and handle them foreach($profileValues as $property => $valueFromLDAP) { // check and update profile properties @@ -604,17 +615,21 @@ class User { try { $accountProperty = $account->getProperty($property); $currentValue = $accountProperty->getValue(); - $scope = ($accountProperty->getScope() ? $accountProperty->getScope() : $defaultScopes[$property]); + $scope = ($accountProperty->getScope() ? $accountProperty->getScope() + : $defaultScopes[$property]); } catch (PropertyDoesNotExistException $e) { // thrown at getProperty - $this->logger->error('property does not exist: '.$property.' for uid='.$this->uid.'', ['app' => 'user_ldap', 'exception' => $e]); + $this->logger->error('property does not exist: '.$property + .' for uid='.$this->uid.'' + , ['app' => 'user_ldap', 'exception' => $e]); $currentValue = ''; $scope = $defaultScopes[$property]; } $verified = IAccountManager::VERIFIED; // trust the LDAP admin knew what he put there if ($currentValue !== $value) { $account->setProperty($property,$value,$scope,$verified); - $this->logger->debug('update property: '.$property.'='.$value.' for uid='.$this->uid.'', ['app' => 'user_ldap']); + $this->logger->debug('update user profile: '.$property.'='.$value + .' for uid='.$this->uid.'', ['app' => 'user_ldap']); } } $accountManager->updateAccount($account); From 72d0a3f26e41b5edb0521cf61bc87d6c08389ced Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Sun, 26 Mar 2023 20:13:20 +0200 Subject: [PATCH 20/23] added simple data conversion for LDAP attributes Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index f44ea8f9084..6c38cba7039 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -250,14 +250,20 @@ class User { //User Profile Field - website $attr = strtolower($this->connection->ldapAttributeWebsite); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] - = $ldapEntry[$attr][0]; + if (str_contains($ldapEntry[$attr][0],' ')) { + // drop appended label + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] + = substr($ldapEntry[$attr][0],0,strpos($ldapEntry[$attr][0]," ")); + } else { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] + = $ldapEntry[$attr][0]; + } } //User Profile Field - Address $attr = strtolower($this->connection->ldapAttributeAddress); if (isset($ldapEntry[$attr])) { - // basic format conversion from postalAddress syntax to comma delimited if (str_contains($ldapEntry[$attr][0],'$')) { + // basic format conversion from postalAddress syntax to commata delimited $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_ADDRESS] = str_replace('$', ", ", $ldapEntry[$attr][0]); } else { @@ -298,8 +304,14 @@ class User { //User Profile Field - biography $attr = strtolower($this->connection->ldapAttributeBiography); if (isset($ldapEntry[$attr])) { - $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] - = $ldapEntry[$attr][0]; + if (str_contains($ldapEntry[$attr][0],'\r')) { + // convert line endings + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] + = str_replace(array("\r\n","\r"), "\n", $ldapEntry[$attr][0]); + } else { + $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_BIOGRAPHY] + = $ldapEntry[$attr][0]; + } } // Update user profile $this->updateProfile($profileValues); @@ -481,7 +493,7 @@ class User { * @brief checks whether an update method specified by feature was run * already. If not, it will marked like this, because it is expected that * the method will be run, when false is returned. - * @param string $feature email | quota | avatar (can be extended) + * @param string $feature email | quota | avatar | profile (can be extended) * @return bool */ private function wasRefreshed($feature) { @@ -632,7 +644,7 @@ class User { .' for uid='.$this->uid.'', ['app' => 'user_ldap']); } } - $accountManager->updateAccount($account); + $accountManager->updateAccount($account); // may throw InvalidArgumentException } /** From ebb0c53f9e271cc0036c5f5c8d6316722a78b33c Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 31 Mar 2023 11:42:11 +0200 Subject: [PATCH 21/23] trying to make github-code-scanning bot happy Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 6c38cba7039..f6a2d037ea7 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -250,10 +250,11 @@ class User { //User Profile Field - website $attr = strtolower($this->connection->ldapAttributeWebsite); if (isset($ldapEntry[$attr])) { - if (str_contains($ldapEntry[$attr][0],' ')) { + $cutPosition = strpos($ldapEntry[$attr][0]," "); + if ($cutPosition) { // drop appended label $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] - = substr($ldapEntry[$attr][0],0,strpos($ldapEntry[$attr][0]," ")); + = substr($ldapEntry[$attr][0],0,$cutPosition); } else { $profileValues[\OCP\Accounts\IAccountManager::PROPERTY_WEBSITE] = $ldapEntry[$attr][0]; From eec5e702da5ce7e6a65adb56ad611aee4c97f718 Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Tue, 11 Apr 2023 16:40:00 +0200 Subject: [PATCH 22/23] error handling in update profile from LDAP added error message on InvalidArgumentException Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index f6a2d037ea7..8685ba0c60a 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -645,7 +645,13 @@ class User { .' for uid='.$this->uid.'', ['app' => 'user_ldap']); } } - $accountManager->updateAccount($account); // may throw InvalidArgumentException + try { + $accountManager->updateAccount($account); // may throw InvalidArgumentException + } catch (\InvalidArgumentException $e) { + $this->logger->error('invalid data from LDAP: for uid='.$this->uid.'' + , ['app' => 'user_ldap', 'func' => 'updateProfile' + , 'exception' => $e]); + } } /** From 64914593a0b3157a67621188a062e722b34976bd Mon Sep 17 00:00:00 2001 From: Marc Hefter Date: Fri, 14 Apr 2023 11:08:46 +0200 Subject: [PATCH 23/23] optimized handling of user profile data change Check profile data checksum before updating user profile, to ensure data has changed. Write checksum to user settings and cache. Signed-off-by: Marc Hefter --- apps/user_ldap/lib/User/User.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php index 8685ba0c60a..f6a3bf70792 100644 --- a/apps/user_ldap/lib/User/User.php +++ b/apps/user_ldap/lib/User/User.php @@ -237,9 +237,15 @@ class User { } unset($attr); + // check for cached profile data + $username = $this->getUsername(); // buffer variable, to save resource + $cacheKey = 'getUserProfile-'.$username; + $profileCached = $this->connection->getFromCache($cacheKey); // honoring profile disabled in config.php and check if user profile was refreshed if ($this->config->getSystemValueBool('profile.enabled', true) && + ($profileCached === null) && // no cache or TTL not expired !$this->wasRefreshed('profile')) { + // check current data $profileValues = array(); //User Profile Field - Phone number $attr = strtolower($this->connection->ldapAttributePhone); @@ -314,9 +320,25 @@ class User { = $ldapEntry[$attr][0]; } } + // check for changed data and cache just for TTL checking + $checksum = hash('sha256', json_encode($profileValues)); + $this->connection->writeToCache($cacheKey + , $checksum // write array to cache. is waste of cache space + , null); // use ldapCacheTTL from configuration // Update user profile - $this->updateProfile($profileValues); + if ($this->config->getUserValue($username, 'user_ldap', 'lastProfileChecksum', null) !== $checksum) { + $this->config->setUserValue($username, 'user_ldap', 'lastProfileChecksum', $checksum); + $this->updateProfile($profileValues); + $this->logger->info("updated profile uid=$username" + , ['app' => 'user_ldap']); + } else { + $this->logger->debug("profile data from LDAP unchanged" + , ['app' => 'user_ldap', 'uid' => $username]); + } unset($attr); + } elseif ($profileCached !== null) { // message delayed, to declutter log + $this->logger->debug("skipping profile check, while cached data exist" + , ['app' => 'user_ldap', 'uid' => $username]); } //Avatar