Skip to content

Commit

Permalink
Merge pull request #44013 from nextcloud/fieat/profile-pronounces
Browse files Browse the repository at this point in the history
feat: add pronouns to account profile
  • Loading branch information
skjnldsv authored Sep 17, 2024
2 parents eb374a7 + b24e02e commit 6bcab26
Show file tree
Hide file tree
Showing 30 changed files with 938 additions and 779 deletions.
1 change: 1 addition & 0 deletions apps/provisioning_api/lib/Controller/AUserData.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ protected function getUserData(string $userId, bool $includeScopes = false): ?ar
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
] as $propertyName) {
$property = $userAccount->getProperty($propertyName);
$data[$propertyName] = $property->getValue();
Expand Down
8 changes: 7 additions & 1 deletion apps/provisioning_api/lib/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,7 @@ public function getEditableFieldsForUser(string $userId): DataResponse {
$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;

return new DataResponse($permittedFields);
}
Expand Down Expand Up @@ -944,6 +945,8 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$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;
Expand All @@ -955,8 +958,8 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$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());
Expand Down Expand Up @@ -997,6 +1000,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$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;
Expand Down Expand Up @@ -1141,6 +1145,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon
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);
Expand Down Expand Up @@ -1189,6 +1194,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon
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);
Expand Down
2 changes: 2 additions & 0 deletions apps/provisioning_api/lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
* phoneScope?: Provisioning_APIUserDetailsScope,
* profile_enabled: string,
* profile_enabledScope?: Provisioning_APIUserDetailsScope,
* pronouns: string,
* pronounsScope?: Provisioning_APIUserDetailsScope,
* quota: Provisioning_APIUserDetailsQuota,
* role: string,
* roleScope?: Provisioning_APIUserDetailsScope,
Expand Down
7 changes: 7 additions & 0 deletions apps/provisioning_api/openapi-administration.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"organisation",
"phone",
"profile_enabled",
"pronouns",
"quota",
"role",
"subadmin",
Expand Down Expand Up @@ -226,6 +227,12 @@
"profile_enabledScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"pronouns": {
"type": "string"
},
"pronounsScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"quota": {
"$ref": "#/components/schemas/UserDetailsQuota"
},
Expand Down
7 changes: 7 additions & 0 deletions apps/provisioning_api/openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
"organisation",
"phone",
"profile_enabled",
"pronouns",
"quota",
"role",
"subadmin",
Expand Down Expand Up @@ -273,6 +274,12 @@
"profile_enabledScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"pronouns": {
"type": "string"
},
"pronounsScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"quota": {
"$ref": "#/components/schemas/UserDetailsQuota"
},
Expand Down
7 changes: 7 additions & 0 deletions apps/provisioning_api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
"organisation",
"phone",
"profile_enabled",
"pronouns",
"quota",
"role",
"subadmin",
Expand Down Expand Up @@ -273,6 +274,12 @@
"profile_enabledScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"pronouns": {
"type": "string"
},
"pronounsScope": {
"$ref": "#/components/schemas/UserDetailsScope"
},
"quota": {
"$ref": "#/components/schemas/UserDetailsQuota"
},
Expand Down
18 changes: 16 additions & 2 deletions apps/provisioning_api/tests/Controller/UsersControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ public function testGetUserDataAsAdmin(): void {
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')
Expand Down Expand Up @@ -1068,6 +1069,7 @@ public function testGetUserDataAsAdmin(): void {
'profile_enabled' => '1',
'notify_email' => null,
'manager' => '',
'pronouns' => 'they/them',
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
Expand Down Expand Up @@ -1171,6 +1173,7 @@ public function testGetUserDataAsSubAdminAndUserIsAccessible(): void {
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
]);

$this->l10nFactory
Expand Down Expand Up @@ -1209,6 +1212,7 @@ public function testGetUserDataAsSubAdminAndUserIsAccessible(): void {
'profile_enabled' => '1',
'notify_email' => null,
'manager' => '',
'pronouns' => 'they/them',
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
Expand Down Expand Up @@ -1351,6 +1355,7 @@ public function testGetUserDataAsSubAdminSelfLookup(): void {
IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
]);

$this->l10nFactory
Expand Down Expand Up @@ -1388,6 +1393,7 @@ public function testGetUserDataAsSubAdminSelfLookup(): void {
'profile_enabled' => '1',
'notify_email' => null,
'manager' => '',
'pronouns' => 'they/them',
];
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
}
Expand Down Expand Up @@ -1729,6 +1735,7 @@ public function selfEditChangePropertyProvider() {
[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'],
];
}

Expand Down Expand Up @@ -1806,6 +1813,7 @@ public function selfEditChangePropertyScopeProvider() {
[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],
];
}

Expand Down Expand Up @@ -3690,7 +3698,8 @@ public function testGetCurrentUserLoggedIn(): void {
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1'
'profile_enabled' => '1',
'pronouns' => 'they/them',
]
);

Expand All @@ -3711,6 +3720,7 @@ public function testGetCurrentUserLoggedIn(): void {
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1',
'pronouns' => 'they/them',
];

$this->assertSame($expected, $api->getCurrentUser()->getData());
Expand Down Expand Up @@ -3775,7 +3785,8 @@ public function testGetUser(): void {
'role' => 'role',
'headline' => 'headline',
'biography' => 'biography',
'profile_enabled' => '1'
'profile_enabled' => '1',
'pronouns' => 'they/them',
];

$api->expects($this->exactly(2))
Expand Down Expand Up @@ -4115,6 +4126,7 @@ public function dataGetEditableFields() {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
]],
[true, ISetDisplayNameBackend::class, [
IAccountManager::PROPERTY_DISPLAYNAME,
Expand All @@ -4130,6 +4142,7 @@ public function dataGetEditableFields() {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
]],
[true, UserInterface::class, [
IAccountManager::PROPERTY_EMAIL,
Expand All @@ -4144,6 +4157,7 @@ public function dataGetEditableFields() {
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
IAccountManager::PROPERTY_PRONOUNS,
]],
];
}
Expand Down
5 changes: 5 additions & 0 deletions apps/settings/lib/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ public function setUserSettings(?string $avatarScope = null,
?string $fediverseScope = null,
?string $birthdate = null,
?string $birthdateScope = null,
?string $pronouns = null,
?string $pronounsScope = null
) {
$user = $this->userSession->getUser();
if (!$user instanceof IUser) {
Expand Down Expand Up @@ -375,6 +377,7 @@ public function setUserSettings(?string $avatarScope = null,
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) {
Expand Down Expand Up @@ -418,6 +421,8 @@ public function setUserSettings(?string $avatarScope = null,
'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'),
],
],
Expand Down
1 change: 1 addition & 0 deletions apps/settings/lib/Settings/Personal/PersonalInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public function getForm(): TemplateResponse {
'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 = [
Expand Down
45 changes: 45 additions & 0 deletions apps/settings/src/components/PersonalInfo/PronounsSection.vue
Original file line number Diff line number Diff line change
@@ -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>
13 changes: 9 additions & 4 deletions apps/settings/src/constants/AccountPropertyConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,40 @@ 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 */
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({
Expand All @@ -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 */
Expand All @@ -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,
})

/**
Expand Down Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit 6bcab26

Please sign in to comment.