Merge pull request #28840 from nextcloud/enh/noid/notification-email-chooser

let user choose notification email in user settings
This commit is contained in:
blizzz 2021-09-15 17:33:05 +02:00 committed by GitHub
commit e26664ba42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 166 additions and 65 deletions

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

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

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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -231,7 +231,7 @@ class PersonalInfo implements ISettings {
* @return array
*/
private function getEmails(IAccount $account): array {
$primaryEmail = [
$systemEmail = [
'value' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue(),
'scope' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(),
'verified' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getVerified(),
@ -243,14 +243,16 @@ class PersonalInfo implements ISettings {
'value' => $property->getValue(),
'scope' => $property->getScope(),
'verified' => $property->getVerified(),
'locallyVerified' => $property->getLocallyVerified(),
];
},
$account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)->getProperties()
);
$emails = [
'primaryEmail' => $primaryEmail,
'primaryEmail' => $systemEmail,
'additionalEmails' => $additionalEmails,
'notificationEmail' => (string)$account->getUser()->getPrimaryEMailAddress(),
];
return $emails;

View file

@ -65,11 +65,19 @@
@click.stop.prevent="deleteEmail">
{{ deleteEmailLabel }}
</ActionButton>
<ActionButton v-if="!primary || !isNotificationEmail"
:aria-label="setNotificationMailLabel"
:close-after-click="true"
:disabled="setNotificationMailDisabled"
icon="icon-favorite"
@click.stop.prevent="setNotificationMail">
{{ setNotificationMailLabel }}
</ActionButton>
</Actions>
</div>
</div>
<em v-if="primary">
<em v-if="isNotificationEmail">
{{ t('settings', 'Primary email for password reset and notifications') }}
</em>
</div>
@ -83,8 +91,15 @@ import debounce from 'debounce'
import FederationControl from '../shared/FederationControl'
import { ACCOUNT_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'
import { savePrimaryEmail, saveAdditionalEmail, saveAdditionalEmailScope, updateAdditionalEmail, removeAdditionalEmail } from '../../../service/PersonalInfo/EmailService'
import { ACCOUNT_PROPERTY_READABLE_ENUM, VERIFICATION_ENUM } from '../../../constants/AccountPropertyConstants'
import {
removeAdditionalEmail,
saveAdditionalEmail,
saveAdditionalEmailScope,
saveNotificationEmail,
savePrimaryEmail,
updateAdditionalEmail,
} from '../../../service/PersonalInfo/EmailService'
import { validateEmail } from '../../../utils/validate'
export default {
@ -113,6 +128,14 @@ export default {
type: String,
required: true,
},
activeNotificationEmail: {
type: String,
default: '',
},
localVerificationState: {
type: Number,
default: VERIFICATION_ENUM.NOT_VERIFIED,
},
},
data() {
@ -145,6 +168,19 @@ export default {
return t('settings', 'Delete email')
},
setNotificationMailDisabled() {
return !this.primary && this.localVerificationState !== VERIFICATION_ENUM.VERIFIED
},
setNotificationMailLabel() {
if (this.isNotificationEmail) {
return t('settings', 'Unset as primary email')
} else if (!this.primary && this.localVerificationState !== VERIFICATION_ENUM.VERIFIED) {
return t('settings', 'This address is not confirmed')
}
return t('settings', 'Set as primary mail')
},
federationDisabled() {
return !this.initialEmail
},
@ -162,6 +198,11 @@ export default {
}
return t('settings', 'Additional email address {index}', { index: this.index + 1 })
},
isNotificationEmail() {
return (this.email === this.activeNotificationEmail)
|| (this.primary && this.activeNotificationEmail === '')
},
},
mounted() {
@ -239,6 +280,22 @@ export default {
}
},
async setNotificationMail() {
try {
const newNotificationMailValue = (this.primary || this.isNotificationEmail) ? '' : this.initialEmail
const responseData = await saveNotificationEmail(newNotificationMailValue)
this.handleResponse({
notificationEmail: newNotificationMailValue,
status: responseData.ocs?.meta?.status,
})
} catch (e) {
this.handleResponse({
errorMessage: 'Unable to choose this email for notifications',
error: e,
})
}
},
async updateAdditionalEmail(email) {
try {
const responseData = await updateAdditionalEmail(this.initialEmail, email)
@ -276,10 +333,14 @@ export default {
}
},
handleResponse({ email, status, errorMessage, error }) {
handleResponse({ email, notificationEmail, status, errorMessage, error }) {
if (status === 'ok') {
// Ensure that local state reflects server state
this.initialEmail = email
if (email) {
this.initialEmail = email
} else if (notificationEmail !== undefined) {
this.$emit('update:notification-email', notificationEmail)
}
this.showCheckmarkIcon = true
setTimeout(() => { this.showCheckmarkIcon = false }, 2000)
} else {

View file

@ -36,7 +36,9 @@
:primary="true"
:scope.sync="primaryEmail.scope"
:email.sync="primaryEmail.value"
@update:email="onUpdateEmail" />
:active-notification-email.sync="notificationEmail"
@update:email="onUpdateEmail"
@update:notification-email="onUpdateNotificationEmail" />
</template>
<span v-else>
{{ primaryEmail.value || t('settings', 'No email address set') }}
@ -46,7 +48,10 @@
:index="index"
:scope.sync="additionalEmail.scope"
:email.sync="additionalEmail.value"
:local-verification-state="parseInt(additionalEmail.locallyVerified, 10)"
:active-notification-email.sync="notificationEmail"
@update:email="onUpdateEmail"
@update:notification-email="onUpdateNotificationEmail"
@delete-additional-email="onDeleteAdditionalEmail(index)" />
</section>
</template>
@ -62,7 +67,7 @@ import { ACCOUNT_PROPERTY_READABLE_ENUM, DEFAULT_ADDITIONAL_EMAIL_SCOPE } from '
import { savePrimaryEmail, savePrimaryEmailScope, removeAdditionalEmail } from '../../../service/PersonalInfo/EmailService'
import { validateEmail } from '../../../utils/validate'
const { emails: { additionalEmails, primaryEmail } } = loadState('settings', 'personalInfoParameters', {})
const { emails: { additionalEmails, primaryEmail, notificationEmail } } = loadState('settings', 'personalInfoParameters', {})
const { displayNameChangeSupported } = loadState('settings', 'accountParameters', {})
export default {
@ -80,6 +85,7 @@ export default {
displayNameChangeSupported,
primaryEmail,
savePrimaryEmailScope,
notificationEmail,
}
},
@ -126,6 +132,10 @@ export default {
}
},
async onUpdateNotificationEmail(email) {
this.notificationEmail = email
},
async updatePrimaryEmail() {
try {
const responseData = await savePrimaryEmail(this.primaryEmailValue)

View file

@ -33,6 +33,7 @@ export const ACCOUNT_PROPERTY_ENUM = Object.freeze({
DISPLAYNAME: 'displayname',
EMAIL: 'email',
EMAIL_COLLECTION: 'additional_mail',
NOTIFICATION_EMAIL: 'notify_email',
PHONE: 'phone',
TWITTER: 'twitter',
WEBSITE: 'website',
@ -118,6 +119,13 @@ export const SCOPE_PROPERTY_ENUM = Object.freeze({
/** Default additional email scope */
export const DEFAULT_ADDITIONAL_EMAIL_SCOPE = SCOPE_ENUM.LOCAL
/** Enum of verification constants, according to IAccountManager */
export const VERIFICATION_ENUM = Object.freeze({
NOT_VERIFIED: 0,
VERIFICATION_IN_PROGRESS: 1,
VERIFIED: 2,
})
/**
* Email validation regex
*

View file

@ -69,6 +69,26 @@ export const saveAdditionalEmail = async(email) => {
return res.data
}
/**
* Save the notification email of the user
*
* @param {string} email the notification email
* @returns {object}
*/
export const saveNotificationEmail = async(email) => {
const userId = getCurrentUser().uid
const url = generateOcsUrl('cloud/users/{userId}', { userId })
await confirmPassword()
const res = await axios.put(url, {
key: ACCOUNT_PROPERTY_ENUM.NOTIFICATION_EMAIL,
value: email,
})
return res.data
}
/**
* Remove an additional email of the user
*