Skip to content

Commit

Permalink
Merge pull request #46592 from nextcloud/feat/first-day-of-week-user-…
Browse files Browse the repository at this point in the history
…setting

feat: let users configure their first day of week
  • Loading branch information
st3iny authored Jul 23, 2024
2 parents e54d39b + b37fb43 commit ee6f857
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 8 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 @@ -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';
Expand Down
13 changes: 13 additions & 0 deletions apps/provisioning_api/lib/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$this->groupManager->isAdmin($currentLoggedInUser->getUID())
) {
$permittedFields[] = self::USER_FIELD_LOCALE;
$permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
}

$permittedFields[] = IAccountManager::PROPERTY_PHONE;
Expand Down Expand Up @@ -965,6 +966,7 @@ public function editUser(string $userId, string $key, string $value): DataRespon
$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;
Expand Down Expand Up @@ -1056,6 +1058,17 @@ public function editUser(string $userId, string $key, string $value): DataRespon
}
$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)) {
Expand Down
2 changes: 2 additions & 0 deletions apps/settings/lib/Settings/Personal/PersonalInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

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;
Expand Down Expand Up @@ -141,6 +142,7 @@ public function getForm(): TemplateResponse {
'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 = [
Expand Down
126 changes: 126 additions & 0 deletions apps/settings/src/components/PersonalInfo/FirstDayOfWeekSection.vue
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export default {
}
&.setting-property {
height: 44px;
height: 34px;
}
label {
Expand Down
2 changes: 2 additions & 0 deletions apps/settings/src/constants/AccountPropertyConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions apps/settings/src/main-personal-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -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())

Expand All @@ -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')
Expand All @@ -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) {
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 @@ -61,6 +61,9 @@
<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>
Expand Down
4 changes: 2 additions & 2 deletions dist/settings-vue-settings-admin-basic-settings.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/settings-vue-settings-admin-basic-settings.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/settings-vue-settings-personal-info.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/settings-vue-settings-personal-info.js.map

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion lib/private/Template/JSConfigHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
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;
Expand Down Expand Up @@ -133,6 +134,9 @@ public function getConfig(): string {

$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,
Expand Down Expand Up @@ -220,7 +224,7 @@ public function getConfig(): string {
$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' => [
Expand Down

0 comments on commit ee6f857

Please sign in to comment.