Skip to content

Commit

Permalink
feat: add profile pronouns
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Sep 17, 2024
1 parent dc71cb7 commit 64549d0
Show file tree
Hide file tree
Showing 21 changed files with 185 additions and 38 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
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
63 changes: 63 additions & 0 deletions apps/settings/src/components/PersonalInfo/PronounsSection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!--
- @copyright Copyright (c) 2024 John Molakvoæ <skjnldsv@protonmail.com>
-
- @author John Molakvoæ <skjnldsv@protonmail.com>
-
- @license AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<template>
<AccountPropertySection v-bind.sync="pronouns"
autocomplete="organization-title"
: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
35 changes: 19 additions & 16 deletions apps/settings/src/main-personal-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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')
Expand All @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions apps/settings/templates/settings/personal/personal.info.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
<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>
Expand Down
Loading

0 comments on commit 64549d0

Please sign in to comment.