Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
John Molakvoæ (skjnldsv) 2024-09-17 21:41:45 +02:00
Родитель dc71cb7c3a
Коммит 26abc86eca
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 60C25B8C072916CF
29 изменённых файлов: 199 добавлений и 54 удалений

Просмотреть файл

@ -179,6 +179,7 @@ abstract class AUserData extends OCSController {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
] as $propertyName) {
$property = $userAccount->getProperty($propertyName);
$data[$propertyName] = $property->getValue();

Просмотреть файл

@ -761,6 +761,7 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
return new DataResponse($permittedFields);
}
@ -944,6 +945,8 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
$permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE;
$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
@ -955,8 +958,8 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX;
// If admin they can edit their own quota and manager
$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
@ -997,6 +1000,7 @@ class UsersController extends AUserData {
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
$permittedFields[] = self::USER_FIELD_QUOTA;
$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
$permittedFields[] = self::USER_FIELD_MANAGER;
@ -1141,6 +1145,7 @@ class UsersController extends AUserData {
case IAccountManager::PROPERTY_HEADLINE:
case IAccountManager::PROPERTY_BIOGRAPHY:
case IAccountManager::PROPERTY_BIRTHDATE:
case IAccountManager::PROPERTY_PRONOUNS:
$userAccount = $this->accountManager->getAccount($targetUser);
try {
$userProperty = $userAccount->getProperty($key);
@ -1189,6 +1194,7 @@ class UsersController extends AUserData {
case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
case IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX:
$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
$userAccount = $this->accountManager->getAccount($targetUser);
$userProperty = $userAccount->getProperty($propertyName);

Просмотреть файл

@ -56,6 +56,8 @@ namespace OCA\Provisioning_API;
* phoneScope?: Provisioning_APIUserDetailsScope,
* profile_enabled: string,
* profile_enabledScope?: Provisioning_APIUserDetailsScope,
* pronouns: string,
* pronounsScope?: Provisioning_APIUserDetailsScope,
* quota: Provisioning_APIUserDetailsQuota,
* role: string,
* roleScope?: Provisioning_APIUserDetailsScope,

Просмотреть файл

@ -99,6 +99,7 @@
"organisation",
"phone",
"profile_enabled",
"pronouns",
"quota",
"role",
"subadmin",
@ -226,6 +227,12 @@
"profile_enabledScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"pronouns": {
"type": "string"
},
"pronounsScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"quota": {
"$ref": "#/components/schemas/UserDetailsQuota"
},

Просмотреть файл

@ -146,6 +146,7 @@
"organisation",
"phone",
"profile_enabled",
"pronouns",
"quota",
"role",
"subadmin",
@ -273,6 +274,12 @@
"profile_enabledScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"pronouns": {
"type": "string"
},
"pronounsScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"quota": {
"$ref": "#/components/schemas/UserDetailsQuota"
},

Просмотреть файл

@ -146,6 +146,7 @@
"organisation",
"phone",
"profile_enabled",
"pronouns",
"quota",
"role",
"subadmin",
@ -273,6 +274,12 @@
"profile_enabledScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"pronouns": {
"type": "string"
},
"pronounsScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"quota": {
"$ref": "#/components/schemas/UserDetailsQuota"
},

Просмотреть файл

@ -990,6 +990,7 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
]);
$this->config
->method('getUserValue')
@ -1068,6 +1069,7 @@ class UsersControllerTest extends TestCase {
'profile_enabled' => '1',
'notify_email' => null,
'manager' => '',
'pronouns' => 'they/them',
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
@ -1171,6 +1173,7 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
]);
$this->l10nFactory
@ -1209,6 +1212,7 @@ class UsersControllerTest extends TestCase {
'profile_enabled' => '1',
'notify_email' => null,
'manager' => '',
'pronouns' => 'they/them',
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
@ -1351,6 +1355,7 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
]);
$this->l10nFactory
@ -1388,6 +1393,7 @@ class UsersControllerTest extends TestCase {
'profile_enabled' => '1',
'notify_email' => null,
'manager' => '',
'pronouns' => 'they/them',
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
@ -1729,6 +1735,7 @@ class UsersControllerTest extends TestCase {
[IAccountManager::PROPERTY_HEADLINE, 'Hi', 'Hello'],
[IAccountManager::PROPERTY_BIOGRAPHY, 'A biography', 'Another biography'],
[IAccountManager::PROPERTY_PROFILE_ENABLED, '1', '0'],
[IAccountManager::PROPERTY_PRONOUNS, 'they/them', 'he/him'],
];
}
@ -1806,6 +1813,7 @@ class UsersControllerTest extends TestCase {
[IAccountManager::PROPERTY_HEADLINE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_BIOGRAPHY, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_PROFILE_ENABLED, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
[IAccountManager::PROPERTY_PRONOUNS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
];
}
@ -3690,7 +3698,8 @@ class UsersControllerTest extends TestCase {
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1'
'profile_enabled' => '1',
'pronouns' => 'they/them',
]
);
@ -3711,6 +3720,7 @@ class UsersControllerTest extends TestCase {
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1',
'pronouns' => 'they/them',
];
$this->assertSame($expected, $api->getCurrentUser()->getData());
@ -3775,7 +3785,8 @@ class UsersControllerTest extends TestCase {
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1'
'profile_enabled' => '1',
'pronouns' => 'they/them',
];
$api->expects($this->exactly(2))
@ -4115,6 +4126,7 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
]],
[true, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_DISPLAYNAME,
@ -4130,6 +4142,7 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
]],
[true, UserInterface::class, [
IAccountManager::PROPERTY_EMAIL,
@ -4144,6 +4157,7 @@ class UsersControllerTest extends TestCase {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
]],
];
}

Просмотреть файл

@ -335,6 +335,8 @@ class UsersController extends Controller {
?string $fediverseScope = null,
?string $birthdate = null,
?string $birthdateScope = null,
?string $pronouns = null,
?string $pronounsScope = null
) {
$user = $this->userSession->getUser();
if (!$user instanceof IUser) {
@ -375,6 +377,7 @@ class UsersController extends Controller {
IAccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope],
IAccountManager::PROPERTY_FEDIVERSE => ['value' => $fediverse, 'scope' => $fediverseScope],
IAccountManager::PROPERTY_BIRTHDATE => ['value' => $birthdate, 'scope' => $birthdateScope],
IAccountManager::PROPERTY_PRONOUNS => ['value' => $pronouns, 'scope' => $pronounsScope],
];
$allowUserToChangeDisplayName = $this->config->getSystemValueBool('allow_user_to_change_display_name', true);
foreach ($updatable as $property => $data) {
@ -418,6 +421,8 @@ class UsersController extends Controller {
'fediverseScope' => $userAccount->getProperty(IAccountManager::PROPERTY_FEDIVERSE)->getScope(),
'birthdate' => $userAccount->getProperty(IAccountManager::PROPERTY_BIRTHDATE)->getValue(),
'birthdateScope' => $userAccount->getProperty(IAccountManager::PROPERTY_BIRTHDATE)->getScope(),
'pronouns' => $userAccount->getProperty(IAccountManager::PROPERTY_PRONOUNS)->getValue(),
'pronounsScope' => $userAccount->getProperty(IAccountManager::PROPERTY_PRONOUNS)->getScope(),
'message' => $this->l10n->t('Settings saved'),
],
],

Просмотреть файл

@ -143,6 +143,7 @@ class PersonalInfo implements ISettings {
'biography' => $this->getProperty($account, IAccountManager::PROPERTY_BIOGRAPHY),
'birthdate' => $this->getProperty($account, IAccountManager::PROPERTY_BIRTHDATE),
'firstDayOfWeek' => $this->config->getUserValue($uid, 'core', AUserData::USER_FIELD_FIRST_DAY_OF_WEEK),
'pronouns' => $this->getProperty($account, IAccountManager::PROPERTY_PRONOUNS),
];
$accountParameters = [

Просмотреть файл

@ -0,0 +1,45 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<AccountPropertySection v-bind.sync="pronouns"
:placeholder="randomPronounsPlaceholder" />
</template>
<script>
import { loadState } from '@nextcloud/initial-state'
import AccountPropertySection from './shared/AccountPropertySection.vue'
import { NAME_READABLE_ENUM } from '../../constants/AccountPropertyConstants.js'
const { pronouns } = loadState('settings', 'personalInfoParameters', {})
export default {
name: 'PronounsSection',
components: {
AccountPropertySection,
},
data() {
return {
pronouns: { ...pronouns, readable: NAME_READABLE_ENUM[pronouns.name] },
}
},
computed: {
randomPronounsPlaceholder() {
const pronouns = [
this.t('settings', 'she/her'),
this.t('settings', 'he/him'),
this.t('settings', 'they/them'),
]
const pronounsExample = pronouns[Math.floor(Math.random() * pronouns.length)]
return this.t('settings', `Your pronouns. E.g. ${pronounsExample}`, { pronounsExample })
},
},
}
</script>

Просмотреть файл

@ -15,19 +15,20 @@ export const ACCOUNT_PROPERTY_ENUM = Object.freeze({
ADDRESS: 'address',
AVATAR: 'avatar',
BIOGRAPHY: 'biography',
BIRTHDATE: 'birthdate',
DISPLAYNAME: 'displayname',
EMAIL_COLLECTION: 'additional_mail',
EMAIL: 'email',
FEDIVERSE: 'fediverse',
HEADLINE: 'headline',
NOTIFICATION_EMAIL: 'notify_email',
FEDIVERSE: 'fediverse',
ORGANISATION: 'organisation',
PHONE: 'phone',
PROFILE_ENABLED: 'profile_enabled',
PRONOUNS: 'pronouns',
ROLE: 'role',
TWITTER: 'twitter',
WEBSITE: 'website',
BIRTHDATE: 'birthdate',
})
/** Enum of account properties to human readable account property names */
@ -35,18 +36,19 @@ export const ACCOUNT_PROPERTY_READABLE_ENUM = Object.freeze({
ADDRESS: t('settings', 'Location'),
AVATAR: t('settings', 'Profile picture'),
BIOGRAPHY: t('settings', 'About'),
BIRTHDATE: t('settings', 'Date of birth'),
DISPLAYNAME: t('settings', 'Full name'),
EMAIL_COLLECTION: t('settings', 'Additional email'),
EMAIL: t('settings', 'Email'),
FEDIVERSE: t('settings', 'Fediverse (e.g. Mastodon)'),
HEADLINE: t('settings', 'Headline'),
ORGANISATION: t('settings', 'Organisation'),
PHONE: t('settings', 'Phone number'),
PROFILE_ENABLED: t('settings', 'Profile'),
PRONOUNS: t('settings', 'Pronouns'),
ROLE: t('settings', 'Role'),
TWITTER: t('settings', 'X (formerly Twitter)'),
FEDIVERSE: t('settings', 'Fediverse (e.g. Mastodon)'),
WEBSITE: t('settings', 'Website'),
BIRTHDATE: t('settings', 'Date of birth'),
})
export const NAME_READABLE_ENUM = Object.freeze({
@ -65,6 +67,7 @@ export const NAME_READABLE_ENUM = Object.freeze({
[ACCOUNT_PROPERTY_ENUM.FEDIVERSE]: ACCOUNT_PROPERTY_READABLE_ENUM.FEDIVERSE,
[ACCOUNT_PROPERTY_ENUM.WEBSITE]: ACCOUNT_PROPERTY_READABLE_ENUM.WEBSITE,
[ACCOUNT_PROPERTY_ENUM.BIRTHDATE]: ACCOUNT_PROPERTY_READABLE_ENUM.BIRTHDATE,
[ACCOUNT_PROPERTY_ENUM.PRONOUNS]: ACCOUNT_PROPERTY_READABLE_ENUM.PRONOUNS,
})
/** Enum of profile specific sections to human readable names */
@ -89,6 +92,7 @@ export const PROPERTY_READABLE_KEYS_ENUM = Object.freeze({
[ACCOUNT_PROPERTY_READABLE_ENUM.FEDIVERSE]: ACCOUNT_PROPERTY_ENUM.FEDIVERSE,
[ACCOUNT_PROPERTY_READABLE_ENUM.WEBSITE]: ACCOUNT_PROPERTY_ENUM.WEBSITE,
[ACCOUNT_PROPERTY_READABLE_ENUM.BIRTHDATE]: ACCOUNT_PROPERTY_ENUM.BIRTHDATE,
[ACCOUNT_PROPERTY_READABLE_ENUM.PRONOUNS]: ACCOUNT_PROPERTY_ENUM.PRONOUNS,
})
/**
@ -134,6 +138,7 @@ export const PROPERTY_READABLE_SUPPORTED_SCOPES_ENUM = Object.freeze({
[ACCOUNT_PROPERTY_READABLE_ENUM.FEDIVERSE]: [SCOPE_ENUM.LOCAL, SCOPE_ENUM.PRIVATE],
[ACCOUNT_PROPERTY_READABLE_ENUM.WEBSITE]: [SCOPE_ENUM.LOCAL, SCOPE_ENUM.PRIVATE],
[ACCOUNT_PROPERTY_READABLE_ENUM.BIRTHDATE]: [SCOPE_ENUM.LOCAL, SCOPE_ENUM.PRIVATE],
[ACCOUNT_PROPERTY_READABLE_ENUM.PRONOUNS]: [SCOPE_ENUM.LOCAL, SCOPE_ENUM.PRIVATE],
})
/** List of readable account properties which aren't published to the lookup server */

Просмотреть файл

@ -9,24 +9,25 @@ import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
import AvatarSection from './components/PersonalInfo/AvatarSection.vue'
import BiographySection from './components/PersonalInfo/BiographySection.vue'
import BirthdaySection from './components/PersonalInfo/BirthdaySection.vue'
import DetailsSection from './components/PersonalInfo/DetailsSection.vue'
import DisplayNameSection from './components/PersonalInfo/DisplayNameSection.vue'
import EmailSection from './components/PersonalInfo/EmailSection/EmailSection.vue'
import PhoneSection from './components/PersonalInfo/PhoneSection.vue'
import LocationSection from './components/PersonalInfo/LocationSection.vue'
import WebsiteSection from './components/PersonalInfo/WebsiteSection.vue'
import TwitterSection from './components/PersonalInfo/TwitterSection.vue'
import FediverseSection from './components/PersonalInfo/FediverseSection.vue'
import FirstDayOfWeekSection from './components/PersonalInfo/FirstDayOfWeekSection.vue'
import HeadlineSection from './components/PersonalInfo/HeadlineSection.vue'
import LanguageSection from './components/PersonalInfo/LanguageSection/LanguageSection.vue'
import LocaleSection from './components/PersonalInfo/LocaleSection/LocaleSection.vue'
import ProfileSection from './components/PersonalInfo/ProfileSection/ProfileSection.vue'
import LocationSection from './components/PersonalInfo/LocationSection.vue'
import OrganisationSection from './components/PersonalInfo/OrganisationSection.vue'
import RoleSection from './components/PersonalInfo/RoleSection.vue'
import HeadlineSection from './components/PersonalInfo/HeadlineSection.vue'
import BiographySection from './components/PersonalInfo/BiographySection.vue'
import PhoneSection from './components/PersonalInfo/PhoneSection.vue'
import ProfileSection from './components/PersonalInfo/ProfileSection/ProfileSection.vue'
import ProfileVisibilitySection from './components/PersonalInfo/ProfileVisibilitySection/ProfileVisibilitySection.vue'
import BirthdaySection from './components/PersonalInfo/BirthdaySection.vue'
import FirstDayOfWeekSection from './components/PersonalInfo/FirstDayOfWeekSection.vue'
import PronounsSection from './components/PersonalInfo/PronounsSection.vue'
import RoleSection from './components/PersonalInfo/RoleSection.vue'
import TwitterSection from './components/PersonalInfo/TwitterSection.vue'
import WebsiteSection from './components/PersonalInfo/WebsiteSection.vue'
__webpack_nonce__ = getCSPNonce()
@ -39,18 +40,19 @@ Vue.mixin({
})
const AvatarView = Vue.extend(AvatarSection)
const BirthdayView = Vue.extend(BirthdaySection)
const DetailsView = Vue.extend(DetailsSection)
const DisplayNameView = Vue.extend(DisplayNameSection)
const EmailView = Vue.extend(EmailSection)
const PhoneView = Vue.extend(PhoneSection)
const LocationView = Vue.extend(LocationSection)
const WebsiteView = Vue.extend(WebsiteSection)
const TwitterView = Vue.extend(TwitterSection)
const FediverseView = Vue.extend(FediverseSection)
const FirstDayOfWeekView = Vue.extend(FirstDayOfWeekSection)
const LanguageView = Vue.extend(LanguageSection)
const LocaleView = Vue.extend(LocaleSection)
const BirthdayView = Vue.extend(BirthdaySection)
const FirstDayOfWeekView = Vue.extend(FirstDayOfWeekSection)
const LocationView = Vue.extend(LocationSection)
const PhoneView = Vue.extend(PhoneSection)
const PronounsView = Vue.extend(PronounsSection)
const TwitterView = Vue.extend(TwitterSection)
const WebsiteView = Vue.extend(WebsiteSection)
new AvatarView().$mount('#vue-avatar-section')
new DetailsView().$mount('#vue-details-section')
@ -65,6 +67,7 @@ new LanguageView().$mount('#vue-language-section')
new LocaleView().$mount('#vue-locale-section')
new FirstDayOfWeekView().$mount('#vue-fdow-section')
new BirthdayView().$mount('#vue-birthday-section')
new PronounsView().$mount('#vue-pronouns-section')
if (profileEnabledGlobally) {
const ProfileView = Vue.extend(ProfileSection)

Просмотреть файл

@ -43,6 +43,9 @@ script('settings', [
<div class="personal-settings-setting-box">
<div id="vue-displayname-section"></div>
</div>
<div class="personal-settings-setting-box">
<div id="vue-pronouns-section"></div>
</div>
<div class="personal-settings-setting-box">
<div id="vue-email-section"></div>
</div>

Просмотреть файл

@ -80,6 +80,8 @@ use Psr\Log\LoggerInterface;
* @property string $ldapAttributeHeadline
* @property string $ldapAttributeBiography
* @property string $ldapAdminGroup
* @property string $ldapAttributeBirthDate
* @property string $ldapAttributePronouns
*/
class Configuration {
public const AVATAR_PREFIX_DEFAULT = 'default';
@ -179,6 +181,7 @@ class Configuration {
'ldapAdminGroup' => '',
'ldapAttributeBirthDate' => null,
'ldapAttributeAnniversaryDate' => null,
'ldapAttributePronouns' => null,
];
public function __construct(string $configPrefix, bool $autoRead = true) {
@ -315,6 +318,7 @@ class Configuration {
case 'ldapAttributeBiography':
case 'ldapAttributeBirthDate':
case 'ldapAttributeAnniversaryDate':
case 'ldapAttributePronouns':
$readMethod = 'getLcValue';
break;
case 'ldapUserDisplayName':
@ -559,6 +563,7 @@ class Configuration {
'ldap_admin_group' => '',
'ldap_attr_birthdate' => '',
'ldap_attr_anniversarydate' => '',
'ldap_attr_pronouns' => '',
];
}
@ -638,6 +643,7 @@ class Configuration {
'ldap_admin_group' => 'ldapAdminGroup',
'ldap_attr_birthdate' => 'ldapAttributeBirthDate',
'ldap_attr_anniversarydate' => 'ldapAttributeAnniversaryDate',
'ldap_attr_pronouns' => 'ldapAttributePronouns',
];
return $array;
}

Просмотреть файл

@ -85,6 +85,7 @@ use Psr\Log\LoggerInterface;
* @property string $ldapAttributeBiography
* @property string $ldapAdminGroup
* @property string $ldapAttributeBirthDate
* @property string $ldapAttributePronouns
*/
class Connection extends LDAPUtility {
private ?\LDAP\Connection $ldapConnectionRes = null;

Просмотреть файл

@ -142,6 +142,7 @@ class Manager {
$this->access->getConnection()->ldapAttributeHeadline,
$this->access->getConnection()->ldapAttributeBiography,
$this->access->getConnection()->ldapAttributeBirthDate,
$this->access->getConnection()->ldapAttributePronouns,
];
$homeRule = (string)$this->access->getConnection()->homeFolderNamingRule;

Просмотреть файл

@ -320,6 +320,12 @@ class User {
]);
}
}
//User Profile Field - pronouns
$attr = strtolower($this->connection->ldapAttributePronouns);
if (!empty($attr)) {
$profileValues[\OCP\Accounts\IAccountManager::PROPERTY_PRONOUNS]
= $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

Просмотреть файл

@ -139,6 +139,7 @@ style('user_ldap', 'settings');
<p><label for="ldap_attr_headline"> <?php p($l->t('Headline Field')); ?></label><input type="text" id="ldap_attr_headline" name="ldap_attr_headline" title="<?php p($l->t('User profile Headline will be set from the specified attribute')); ?>" data-default="<?php p($_['ldap_attr_headline_default']); ?>"></p>
<p><label for="ldap_attr_biography"> <?php p($l->t('Biography Field')); ?></label><input type="text" id="ldap_attr_biography" name="ldap_attr_biography" title="<?php p($l->t('User profile Biography will be set from the specified attribute')); ?>" data-default="<?php p($_['ldap_attr_biography_default']); ?>"></p>
<p><label for="ldap_attr_birthdate"> <?php p($l->t('Birthdate Field')); ?></label><input type="text" id="ldap_attr_birthdate" name="ldap_attr_birthdate" title="<?php p($l->t('User profile Date of birth will be set from the specified attribute')); ?>" data-default="<?php p($_['ldap_attr_birthdate_default']); ?>"></p>
<p></p><label for="ldap_attr_pronouns"> <?php p($l->t('Pronouns Field')); ?></label><input type="text" id="ldap_attr_pronouns" name="ldap_attr_pronouns" title="<?php p($l->t('User profile Pronouns will be set from the specified attribute')); ?>" data-default="<?php p($_['ldap_attr_pronouns_default']); ?>"></p>
</div>
</div>
<?php print_unescaped($_['settingControls']); ?>

Просмотреть файл

@ -75,6 +75,7 @@ Feature: provisioning
| role |
| headline |
| biography |
| pronouns |
| profile_enabled |
Given As an "brand-new-user"
Then user "brand-new-user" has editable fields
@ -90,6 +91,7 @@ Feature: provisioning
| role |
| headline |
| biography |
| pronouns |
| profile_enabled |
Then user "self" has editable fields
| displayname |
@ -104,6 +106,7 @@ Feature: provisioning
| role |
| headline |
| biography |
| pronouns |
| profile_enabled |
Scenario: Edit a user
@ -570,7 +573,7 @@ Feature: provisioning
And group "new-group" does not exist
Scenario: Delete a group with special characters
Given As an "admin"
Given As an "admin"
And group "España" exists
When sending "DELETE" to "/cloud/groups/España"
Then the OCS status code should be "100"

Просмотреть файл

@ -11,6 +11,7 @@
<div class="profile__header__container__placeholder" />
<div class="profile__header__container__displayname">
<h2>{{ displayname || userId }}</h2>
<span v-if="pronouns" class="profile__header__container__pronouns">· {{ pronouns }}</span>
<NcButton v-if="isCurrentUser"
type="primary"
:href="settingsUrl">
@ -177,6 +178,7 @@ export default defineComponent({
biography: null as string|null,
actions: [] as IProfileAction[],
isUserAvatarVisible: false,
pronouns: null as string|null,
})
return {

4
dist/core-profile.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

2
dist/core-profile.js.map поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

4
dist/settings-vue-settings-personal-info.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -64,19 +64,20 @@ class AccountManager implements IAccountManager {
* The list of default scopes for each property.
*/
public const DEFAULT_SCOPES = [
self::PROPERTY_DISPLAYNAME => self::SCOPE_FEDERATED,
self::PROPERTY_ADDRESS => self::SCOPE_LOCAL,
self::PROPERTY_WEBSITE => self::SCOPE_LOCAL,
self::PROPERTY_EMAIL => self::SCOPE_FEDERATED,
self::PROPERTY_AVATAR => self::SCOPE_FEDERATED,
self::PROPERTY_PHONE => self::SCOPE_LOCAL,
self::PROPERTY_TWITTER => self::SCOPE_LOCAL,
self::PROPERTY_FEDIVERSE => self::SCOPE_LOCAL,
self::PROPERTY_ORGANISATION => self::SCOPE_LOCAL,
self::PROPERTY_ROLE => self::SCOPE_LOCAL,
self::PROPERTY_HEADLINE => self::SCOPE_LOCAL,
self::PROPERTY_BIOGRAPHY => self::SCOPE_LOCAL,
self::PROPERTY_BIRTHDATE => self::SCOPE_LOCAL,
self::PROPERTY_DISPLAYNAME => self::SCOPE_FEDERATED,
self::PROPERTY_EMAIL => self::SCOPE_FEDERATED,
self::PROPERTY_FEDIVERSE => self::SCOPE_LOCAL,
self::PROPERTY_HEADLINE => self::SCOPE_LOCAL,
self::PROPERTY_ORGANISATION => self::SCOPE_LOCAL,
self::PROPERTY_PHONE => self::SCOPE_LOCAL,
self::PROPERTY_PRONOUNS => self::SCOPE_FEDERATED,
self::PROPERTY_ROLE => self::SCOPE_LOCAL,
self::PROPERTY_TWITTER => self::SCOPE_LOCAL,
self::PROPERTY_WEBSITE => self::SCOPE_LOCAL,
];
public function __construct(
@ -679,6 +680,12 @@ class AccountManager implements IAccountManager {
'name' => self::PROPERTY_PROFILE_ENABLED,
'value' => $this->isProfileEnabledByDefault($this->config) ? '1' : '0',
],
[
'name' => self::PROPERTY_PRONOUNS,
'value' => '',
'scope' => $scopes[self::PROPERTY_PRONOUNS],
],
];
}

Просмотреть файл

@ -66,6 +66,7 @@ class ProfileManager implements IProfileManager {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_PRONOUNS,
];
public function __construct(
@ -222,7 +223,7 @@ class ProfileManager implements IProfileManager {
/**
* Return the profile parameters of the target user that are visible to the visiting user
* in an associative array
* @return array{userId: string, address?: string|null, biography?: string|null, displayname?: string|null, headline?: string|null, isUserAvatarVisible?: bool, organisation?: string|null, role?: string|null, actions: list<array{id: string, icon: string, title: string, target: ?string}>}
* @return array{userId: string, address?: string|null, biography?: string|null, displayname?: string|null, headline?: string|null, isUserAvatarVisible?: bool, organisation?: string|null, pronouns?: non-falsy-string|null, role?: string|null, actions: list<array{id: string, icon: string, title: string, target: ?string}>}
*/
public function getProfileFields(IUser $targetUser, ?IUser $visitingUser): array {
$account = $this->accountManager->getAccount($targetUser);
@ -241,6 +242,7 @@ class ProfileManager implements IProfileManager {
case IAccountManager::PROPERTY_HEADLINE:
case IAccountManager::PROPERTY_ORGANISATION:
case IAccountManager::PROPERTY_ROLE:
case IAccountManager::PROPERTY_PRONOUNS:
$profileParameters[$property] =
$this->isProfileFieldVisible($property, $targetUser, $visitingUser)
// Explicitly set to null when value is empty string
@ -399,6 +401,10 @@ class ProfileManager implements IProfileManager {
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get('lib')->t('Role'),
],
IAccountManager::PROPERTY_PRONOUNS => [
'appId' => self::CORE_APP_ID,
'displayId' => $this->l10nFactory->get('lib')->t('Pronouns'),
],
];
$paramMetadata = array_merge($actionsMetadata, $propertiesMetadata);

Просмотреть файл

@ -161,26 +161,32 @@ interface IAccountManager {
*/
public const PROPERTY_BIRTHDATE = 'birthdate';
/**
* @since 31.0.0
*/
public const PROPERTY_PRONOUNS = 'pronouns';
/**
* The list of allowed properties
*
* @since 25.0.0
*/
public const ALLOWED_PROPERTIES = [
self::PROPERTY_AVATAR,
self::PROPERTY_DISPLAYNAME,
self::PROPERTY_PHONE,
self::PROPERTY_EMAIL,
self::PROPERTY_WEBSITE,
self::PROPERTY_ADDRESS,
self::PROPERTY_TWITTER,
self::PROPERTY_FEDIVERSE,
self::PROPERTY_ORGANISATION,
self::PROPERTY_ROLE,
self::PROPERTY_HEADLINE,
self::PROPERTY_AVATAR,
self::PROPERTY_BIOGRAPHY,
self::PROPERTY_PROFILE_ENABLED,
self::PROPERTY_BIRTHDATE,
self::PROPERTY_DISPLAYNAME,
self::PROPERTY_EMAIL,
self::PROPERTY_FEDIVERSE,
self::PROPERTY_HEADLINE,
self::PROPERTY_ORGANISATION,
self::PROPERTY_PHONE,
self::PROPERTY_PROFILE_ENABLED,
self::PROPERTY_PRONOUNS,
self::PROPERTY_ROLE,
self::PROPERTY_TWITTER,
self::PROPERTY_WEBSITE,
];