Skip to content

Commit

Permalink
Disable notification emails (#8911)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan authored Apr 27, 2023
1 parent 0d86206 commit 683b0af
Show file tree
Hide file tree
Showing 7 changed files with 350 additions and 152 deletions.
7 changes: 7 additions & 0 deletions changelog/unreleased/enhancement-add-notifications-setting
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Add notification setting to account page

We've added notification setting to the account page,
where the user can turn on or off receiving emails for notifications.

https://github.com/owncloud/web/pull/8911
https://github.com/owncloud/web/issues/8904
257 changes: 183 additions & 74 deletions packages/web-runtime/src/pages/account.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<main id="account" class="oc-height-1-1 oc-m">
<app-loading-spinner v-if="isLoading" />
<main v-else id="account" class="oc-height-1-1 oc-m">
<div class="oc-flex oc-flex-between oc-flex-bottom oc-width-1-1 oc-border-b oc-py">
<h1 id="account-page-title" class="oc-page-title oc-m-rm">{{ pageTitle }}</h1>
<div>
Expand Down Expand Up @@ -68,12 +69,15 @@
/>
</dd>
</div>
<div v-if="isLanguageSupported" class="account-page-info-language oc-mb oc-width-1-2@s">
<div
v-if="isSettingsServiceSupported"
class="account-page-info-language oc-mb oc-width-1-2@s"
>
<dt class="oc-text-normal oc-text-muted" v-text="$gettext('Language')" />
<dd data-testid="language">
<oc-select
v-if="languageOptions"
:model-value="selectedLanguageOption"
:model-value="selectedLanguageValue"
:clearable="false"
:options="languageOptions"
@update:model-value="updateSelectedLanguage"
Expand All @@ -100,45 +104,60 @@
<gdpr-export />
</dd>
</div>
<div v-if="isSettingsServiceSupported" class="account-page-notification oc-mb oc-width-1-2@s">
<dt class="oc-text-normal oc-text-muted" v-text="$gettext('Notifications')" />
<dd data-testid="notification-mails">
<oc-checkbox
:model-value="disableEmailNotificationsValue"
size="large"
:label="$gettext('Receive notification mails')"
data-testid="account-page-notification-mails-checkbox"
@update:model-value="updateDisableEmailNotifications"
/>
</dd>
</div>
</dl>
</main>
</template>

<script lang="ts">
import { mapActions } from 'vuex'
import EditPasswordModal from '../components/EditPasswordModal.vue'
import { computed, defineComponent, onMounted, unref } from 'vue'
import { computed, defineComponent, onMounted, unref, ref } from 'vue'
import {
useAccessToken,
useCapabilityGraphPersonalDataExport,
useCapabilitySpacesEnabled,
useClientService,
useStore
} from 'web-pkg/src/composables'
import { useTask } from 'vue-concurrency'
import axios from 'axios'
import { v4 as uuidV4 } from 'uuid'
import { useGettext } from 'vue3-gettext'
import { setCurrentLanguage } from 'web-runtime/src/helpers/language'
import GdprExport from 'web-runtime/src/components/Account/GdprExport.vue'
import { useConfigurationManager } from 'web-pkg/src/composables/configuration'
import { isPersonalSpaceResource } from 'web-client/src/helpers'
import AppLoadingSpinner from 'web-pkg/src/components/AppLoadingSpinner.vue'
export default defineComponent({
name: 'Personal',
components: {
AppLoadingSpinner,
EditPasswordModal,
GdprExport
},
setup() {
const store = useStore()
const accessToken = useAccessToken({ store })
const language = useGettext()
const { $gettext } = language
const clientService = useClientService()
const configurationManager = useConfigurationManager()
const valuesList = ref()
const bundlesList = ref()
const selectedLanguageValue = ref()
const disableEmailNotificationsValue = ref()
// FIXME: Use graph capability when we have it
const isLanguageSupported = useCapabilitySpacesEnabled()
const isSettingsServiceSupported = useCapabilitySpacesEnabled()
const isChangePasswordEnabled = useCapabilitySpacesEnabled()
const isPersonalDataExportEnabled = useCapabilityGraphPersonalDataExport()
const user = computed(() => {
Expand All @@ -152,113 +171,203 @@ export default defineComponent({
)
})
const loadAccountBundleTask = useTask(function* () {
const loadValuesListTask = useTask(function* () {
try {
const {
data: { values }
} = yield clientService.httpAuthenticated.post('/api/v0/settings/values-list', {
account_uuid: 'me'
})
valuesList.value = values || []
} catch (e) {
console.error(e)
store.dispatch('showMessage', {
title: $gettext('Unable to load account data…'),
status: 'danger'
})
valuesList.value = []
}
}).restartable()
const loadBundlesListTask = useTask(function* () {
try {
const {
data: { bundles }
} = yield axios.post(
'/api/v0/settings/bundles-list',
{},
{
headers: {
authorization: `Bearer ${unref(accessToken)}`,
'X-Request-ID': uuidV4()
}
}
)
return bundles.find((b) => b.extension === 'ocis-accounts')
} = yield clientService.httpAuthenticated.post('/api/v0/settings/bundles-list', {})
bundlesList.value = bundles?.find((b) => b.extension === 'ocis-accounts')
} catch (e) {
console.error(e)
return []
store.dispatch('showMessage', {
title: $gettext('Unable to load account data…'),
status: 'danger'
})
bundlesList.value = []
}
}).restartable()
const accountSettingIdentifier = {
extension: 'ocis-accounts',
bundle: 'profile',
setting: 'language'
}
const languageSetting = computed(() => {
return store.getters.getSettingsValue(accountSettingIdentifier)
const isLoading = computed(() => {
if (!unref(isSettingsServiceSupported)) {
return false
}
return (
loadValuesListTask.isRunning ||
!loadValuesListTask.last ||
loadBundlesListTask.isRunning ||
!loadBundlesListTask.last
)
})
const languageOptions = computed(() => {
const languageOptions = loadAccountBundleTask.last?.value?.settings.find(
(s) => s.name === 'language'
)?.singleChoiceValue.options
const languageOptions = unref(bundlesList)?.settings?.find((s) => s.name === 'language')
?.singleChoiceValue.options
return languageOptions?.map((l) => ({
label: l.displayValue,
value: l.value.stringValue,
default: l.default
}))
})
const selectedLanguageOption = computed(() => {
const current = unref(languageSetting)?.listValue.values[0].stringValue
if (!current) {
return unref(languageOptions).find((o) => o.default)
const groupNames = computed(() => {
if (unref(useCapabilitySpacesEnabled())) {
return unref(user)
.groups.map((group) => group.displayName)
.join(', ')
}
return unref(languageOptions).find((o) => o.value === current)
return unref(user).groups.join(', ')
})
const updateSelectedLanguage = (option) => {
const bundle = loadAccountBundleTask.last?.value
const saveValue = async ({
identifier,
valueOptions
}: {
identifier: string
valueOptions: Record<string, any>
}) => {
const valueId = unref(valuesList)?.find((cV) => cV.identifier.setting === identifier)?.value
?.id
const value = {
bundleId: bundle?.id,
settingId: bundle?.settings.find((s) => s.name === 'language')?.id,
bundleId: unref(bundlesList)?.id,
settingId: unref(bundlesList)?.settings?.find((s) => s.name === identifier)?.id,
resource: { type: 'TYPE_USER' },
listValue: { values: [{ stringValue: option.value }] },
...(unref(languageSetting) && { id: unref(languageSetting).id })
accountUuid: 'me',
...valueOptions,
...(valueId && { id: valueId })
}
axios.post(
'/api/v0/settings/values-save',
{ value: { ...value, accountUuid: 'me' } },
{
headers: {
authorization: `Bearer ${unref(accessToken)}`,
'X-Request-ID': uuidV4()
try {
await clientService.httpAuthenticated.post('/api/v0/settings/values-save', {
value: {
accountUuid: 'me',
...value
}
})
/**
* Edge case: we need to reload the values list to retrieve the valueId if not set,
* otherwise the backend saves multiple entries
*/
if (!valueId) {
loadValuesListTask.perform()
}
)
const newSetting = { identifier: accountSettingIdentifier, value }
store.commit('SET_SETTINGS_VALUE', newSetting)
setCurrentLanguage({ language, languageSetting: newSetting })
return value
} catch (e) {
throw e
}
}
const accountEditLink = computed(() => {
return store.getters.configuration?.options?.accountEditLink
})
const groupNames = computed(() => {
if (unref(useCapabilitySpacesEnabled())) {
return unref(user)
.groups.map((group) => group.displayName)
.join(', ')
const updateSelectedLanguage = async (option) => {
try {
const value = await saveValue({
identifier: 'language',
valueOptions: { listValue: { values: [{ stringValue: option.value }] } }
})
selectedLanguageValue.value = option
setCurrentLanguage({
language,
languageSetting: {
identifier: {
extension: 'ocis-accounts',
bundle: 'profile',
setting: 'language'
},
value
}
})
store.dispatch('showMessage', {
title: $gettext('Language was saved successfully.')
})
} catch (e) {
console.error(e)
store.dispatch('showMessage', {
title: $gettext('Saving language failed…'),
status: 'danger'
})
}
}
return unref(user).groups.join(', ')
})
const updateDisableEmailNotifications = async (option) => {
try {
await saveValue({
identifier: 'disable-email-notifications',
valueOptions: { boolValue: !option }
})
disableEmailNotificationsValue.value = option
store.dispatch('showMessage', {
title: $gettext('Email notifications preference saved successfully.')
})
} catch (e) {
console.error(e)
store.dispatch('showMessage', {
title: $gettext('Unable to save email notifications preference…'),
status: 'danger'
})
}
}
const logoutUrl = computed(() => {
return configurationManager.logoutUrl
})
onMounted(async () => {
if (unref(isSettingsServiceSupported)) {
await loadBundlesListTask.perform()
await loadValuesListTask.perform()
const languageConfiguration = unref(valuesList)?.find(
(cV) => cV.identifier.setting === 'language'
)
selectedLanguageValue.value = languageConfiguration
? unref(languageOptions)?.find(
(lO) => lO.value === languageConfiguration.value?.listValue?.values?.[0]?.stringValue
)
: unref(languageOptions)?.find((o) => o.default)
const disableEmailNotificationsConfiguration = unref(valuesList)?.find(
(cV) => cV.identifier.setting === 'disable-email-notifications'
)
onMounted(() => {
if (unref(isLanguageSupported)) {
loadAccountBundleTask.perform()
disableEmailNotificationsValue.value = disableEmailNotificationsConfiguration
? !disableEmailNotificationsConfiguration.value?.boolValue
: true
}
})
return {
clientService,
languageOptions,
selectedLanguageOption,
selectedLanguageValue,
updateSelectedLanguage,
accountEditLink,
updateDisableEmailNotifications,
accountEditLink: store.getters.configuration?.options?.accountEditLink,
isChangePasswordEnabled,
showGdprExport,
isLanguageSupported,
isSettingsServiceSupported,
groupNames,
user,
logoutUrl
logoutUrl: configurationManager.logoutUrl,
isLoading,
disableEmailNotificationsValue,
loadBundlesListTask,
loadValuesListTask
}
},
data() {
Expand Down
1 change: 0 additions & 1 deletion packages/web-runtime/src/services/auth/userManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ export class UserManager extends OidcUserManager {
let roles
;[graphUser, roles] = await Promise.all([graphClient.users.getMe(), this.fetchRoles()])
this.store.commit('SET_ROLES', roles)
this.store.commit('SET_SETTINGS_VALUES', settings)

role = await this.fetchRole({ graphUser, roles })
} else {
Expand Down
2 changes: 0 additions & 2 deletions packages/web-runtime/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import apps from './apps'
import auth from './auth'
import config from './config'
import user from './user'
import settings from './settings'
import modal from './modal'
import navigation from './navigation'
import spaces from './spaces'
Expand All @@ -24,7 +23,6 @@ export default {
apps,
user,
config,
settings,
modal,
navigation,
runtime
Expand Down
Loading

0 comments on commit 683b0af

Please sign in to comment.