feat: let users configure their first day of week

Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
pull/46592/head
Richard Steinmetz 4 months ago
parent 8cc996155e
commit b37fb43a32
No known key found for this signature in database
GPG Key ID: 27137D9E7D273FB2
  1. 1
      apps/provisioning_api/lib/Controller/AUserData.php
  2. 13
      apps/provisioning_api/lib/Controller/UsersController.php
  3. 2
      apps/settings/lib/Settings/Personal/PersonalInfo.php
  4. 126
      apps/settings/src/components/PersonalInfo/FirstDayOfWeekSection.vue
  5. 2
      apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue
  6. 2
      apps/settings/src/constants/AccountPropertyConstants.js
  7. 3
      apps/settings/src/main-personal-info.js
  8. 3
      apps/settings/templates/settings/personal/personal.info.php
  9. 4
      dist/settings-vue-settings-admin-basic-settings.js
  10. 2
      dist/settings-vue-settings-admin-basic-settings.js.map
  11. 4
      dist/settings-vue-settings-personal-info.js
  12. 2
      dist/settings-vue-settings-personal-info.js.map
  13. 6
      lib/private/Template/JSConfigHelper.php

@ -39,6 +39,7 @@ abstract class AUserData extends OCSController {
public const USER_FIELD_DISPLAYNAME = 'display';
public const USER_FIELD_LANGUAGE = 'language';
public const USER_FIELD_LOCALE = 'locale';
public const USER_FIELD_FIRST_DAY_OF_WEEK = 'first_day_of_week';
public const USER_FIELD_PASSWORD = 'password';
public const USER_FIELD_QUOTA = 'quota';
public const USER_FIELD_MANAGER = 'manager';

@ -913,6 +913,7 @@ class UsersController extends AUserData {
$this->groupManager->isAdmin($currentLoggedInUser->getUID())
) {
$permittedFields[] = self::USER_FIELD_LOCALE;
$permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
}
$permittedFields[] = IAccountManager::PROPERTY_PHONE;
@ -965,6 +966,7 @@ class UsersController extends AUserData {
$permittedFields[] = self::USER_FIELD_PASSWORD;
$permittedFields[] = self::USER_FIELD_LANGUAGE;
$permittedFields[] = self::USER_FIELD_LOCALE;
$permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
$permittedFields[] = IAccountManager::PROPERTY_PHONE;
$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
@ -1056,6 +1058,17 @@ class UsersController extends AUserData {
}
$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
break;
case self::USER_FIELD_FIRST_DAY_OF_WEEK:
$intValue = (int)$value;
if ($intValue < -1 || $intValue > 6) {
throw new OCSException($this->l10n->t('Invalid first day of week'), 102);
}
if ($intValue === -1) {
$this->config->deleteUserValue($targetUser->getUID(), 'core', AUserData::USER_FIELD_FIRST_DAY_OF_WEEK);
} else {
$this->config->setUserValue($targetUser->getUID(), 'core', AUserData::USER_FIELD_FIRST_DAY_OF_WEEK, $value);
}
break;
case self::USER_FIELD_NOTIFICATION_EMAIL:
$success = false;
if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {

@ -11,6 +11,7 @@ namespace OCA\Settings\Settings\Personal;
use OC\Profile\ProfileManager;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCA\Provisioning_API\Controller\AUserData;
use OCP\Accounts\IAccount;
use OCP\Accounts\IAccountManager;
use OCP\Accounts\IAccountProperty;
@ -141,6 +142,7 @@ class PersonalInfo implements ISettings {
'headline' => $this->getProperty($account, IAccountManager::PROPERTY_HEADLINE),
'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),
];
$accountParameters = [

@ -0,0 +1,126 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<section class="fdow-section">
<HeaderBar :input-id="inputId"
:readable="propertyReadable" />
<NcSelect :aria-label-listbox="t('settings', 'Days to use as the first day of week')"
class="fdow-section__day-select"
:clearable="false"
:input-id="inputId"
label="label"
label-outside
:options="dayOptions"
:value="valueOption"
@option:selected="updateFirstDayOfWeek" />
</section>
</template>
<script lang="ts">
import HeaderBar from './shared/HeaderBar.vue'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
import {
ACCOUNT_SETTING_PROPERTY_ENUM,
ACCOUNT_SETTING_PROPERTY_READABLE_ENUM,
} from '../../constants/AccountPropertyConstants'
import { getDayNames, getFirstDay } from '@nextcloud/l10n'
import { savePrimaryAccountProperty } from '../../service/PersonalInfo/PersonalInfoService'
import { handleError } from '../../utils/handlers.ts'
import { loadState } from '@nextcloud/initial-state'
interface DayOption {
value: number,
label: string,
}
const { firstDayOfWeek } = loadState<{firstDayOfWeek?: string}>(
'settings',
'personalInfoParameters',
{},
)
export default {
name: 'FirstDayOfWeekSection',
components: {
HeaderBar,
NcSelect,
},
data() {
let firstDay = -1
if (firstDayOfWeek) {
firstDay = parseInt(firstDayOfWeek)
}
return {
firstDay,
}
},
computed: {
inputId(): string {
return 'account-property-fdow'
},
propertyReadable(): string {
return ACCOUNT_SETTING_PROPERTY_READABLE_ENUM.FIRST_DAY_OF_WEEK
},
dayOptions(): DayOption[] {
const options = [{
value: -1,
label: t('settings', 'Derived from your locale ({weekDayName})', {
weekDayName: getDayNames()[getFirstDay()],
}),
}]
for (const [index, dayName] of getDayNames().entries()) {
options.push({ value: index, label: dayName })
}
return options
},
valueOption(): DayOption | undefined {
return this.dayOptions.find((option) => option.value === this.firstDay)
},
},
methods: {
async updateFirstDayOfWeek(option: DayOption): Promise<void> {
try {
const responseData = await savePrimaryAccountProperty(
ACCOUNT_SETTING_PROPERTY_ENUM.FIRST_DAY_OF_WEEK,
option.value.toString(),
)
this.handleResponse({
value: option.value,
status: responseData.ocs?.meta?.status,
})
window.location.reload()
} catch (e) {
this.handleResponse({
errorMessage: t('settings', 'Unable to update first day of week'),
error: e,
})
}
},
handleResponse({ value, status, errorMessage, error }): void {
if (status === 'ok') {
this.firstDay = value
} else {
this.$emit('update:value', this.firstDay)
handleError(error, errorMessage)
}
},
},
}
</script>
<style lang="scss" scoped>
.fdow-section {
padding: 10px;
&__day-select {
width: 100%;
margin-top: 6px; // align with other inputs
}
}
</style>

@ -130,7 +130,7 @@ export default {
}
&.setting-property {
height: 44px;
height: 34px;
}
label {

@ -99,12 +99,14 @@ export const PROPERTY_READABLE_KEYS_ENUM = Object.freeze({
export const ACCOUNT_SETTING_PROPERTY_ENUM = Object.freeze({
LANGUAGE: 'language',
LOCALE: 'locale',
FIRST_DAY_OF_WEEK: 'first_day_of_week',
})
/** Enum of account setting properties to human readable setting properties */
export const ACCOUNT_SETTING_PROPERTY_READABLE_ENUM = Object.freeze({
LANGUAGE: t('settings', 'Language'),
LOCALE: t('settings', 'Locale'),
FIRST_DAY_OF_WEEK: t('settings', 'First day of week'),
})
/** Enum of scopes */

@ -26,6 +26,7 @@ import HeadlineSection from './components/PersonalInfo/HeadlineSection.vue'
import BiographySection from './components/PersonalInfo/BiographySection.vue'
import ProfileVisibilitySection from './components/PersonalInfo/ProfileVisibilitySection/ProfileVisibilitySection.vue'
import BirthdaySection from './components/PersonalInfo/BirthdaySection.vue'
import FirstDayOfWeekSection from './components/PersonalInfo/FirstDayOfWeekSection.vue'
__webpack_nonce__ = btoa(getRequestToken())
@ -49,6 +50,7 @@ const FediverseView = Vue.extend(FediverseSection)
const LanguageView = Vue.extend(LanguageSection)
const LocaleView = Vue.extend(LocaleSection)
const BirthdayView = Vue.extend(BirthdaySection)
const FirstDayOfWeekView = Vue.extend(FirstDayOfWeekSection)
new AvatarView().$mount('#vue-avatar-section')
new DetailsView().$mount('#vue-details-section')
@ -61,6 +63,7 @@ new TwitterView().$mount('#vue-twitter-section')
new FediverseView().$mount('#vue-fediverse-section')
new LanguageView().$mount('#vue-language-section')
new LocaleView().$mount('#vue-locale-section')
new FirstDayOfWeekView().$mount('#vue-fdow-section')
new BirthdayView().$mount('#vue-birthday-section')
if (profileEnabledGlobally) {

@ -61,6 +61,9 @@ script('settings', [
<div class="personal-settings-setting-box personal-settings-locale-box">
<div id="vue-locale-section"></div>
</div>
<div class="personal-settings-setting-box">
<div id="vue-fdow-section"></div>
</div>
<div class="personal-settings-setting-box">
<div id="vue-website-section"></div>
</div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -12,6 +12,7 @@ use OC\Authentication\Token\IProvider;
use OC\CapabilitiesManager;
use OC\Files\FilenameValidator;
use OC\Share\Share;
use OCA\Provisioning_API\Controller\AUserData;
use OCP\App\AppPathNotFoundException;
use OCP\App\IAppManager;
use OCP\Authentication\Exceptions\ExpiredTokenException;
@ -133,6 +134,9 @@ class JSConfigHelper {
$capabilities = $this->capabilitiesManager->getCapabilities(false, true);
$userFirstDay = $this->config->getUserValue($uid, 'core', AUserData::USER_FIELD_FIRST_DAY_OF_WEEK, null);
$firstDay = (int)($userFirstDay ?? $this->l->l('firstday', null));
$config = [
/** @deprecated 30.0.0 - use files capabilities instead */
'blacklist_files_regex' => FileInfo::BLACKLIST_FILES_REGEX,
@ -220,7 +224,7 @@ class JSConfigHelper {
$this->l->t('Nov.'),
$this->l->t('Dec.')
]),
"firstDay" => json_encode($this->l->l('firstday', null)),
"firstDay" => json_encode($firstDay),
"_oc_config" => json_encode($config),
"oc_appconfig" => json_encode([
'core' => [

Loading…
Cancel
Save