mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
Merge pull request #46592 from nextcloud/feat/first-day-of-week-user-setting
feat: let users configure their first day of week
This commit is contained in:
commit
ee6f857889
13 changed files with 162 additions and 8 deletions
|
|
@ -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
4
dist/settings-vue-settings-personal-info.js
vendored
4
dist/settings-vue-settings-personal-info.js
vendored
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…
Reference in a new issue