Merge pull request #13214 from meteor/feature/add-addemailasync-alias

[Meteor 3] Add Accounts.addEmailAsync alias
This commit is contained in:
Denilson
2024-07-04 14:01:02 -04:00
committed by GitHub
5 changed files with 91 additions and 53 deletions

View File

@@ -53,7 +53,7 @@ insensitive duplicates before updates.
{% apibox "Accounts.setUsername" %}
{% apibox "Accounts.addEmail" %}
{% apibox "Accounts.addEmailAsync" %}
By default, an email address is added with `{ verified: false }`. Use
[`Accounts.sendVerificationEmail`](#Accounts-sendVerificationEmail) to send an

View File

@@ -830,7 +830,7 @@ Meteor.methods(
});
/**
* @summary Add an email asynchronously address for a user. Use this instead of directly
* @summary Asynchronously add an email address for a user. Use this instead of directly
* updating the database. The operation will fail if there is a different user
* with an email only differing in case. If the specified user has an existing
* email only differing in case however, we replace it.
@@ -841,8 +841,7 @@ Meteor.methods(
* be marked as verified. Defaults to false.
* @importFromPackage accounts-base
*/
Accounts.addEmail =
async (userId, newEmail, verified) => {
Accounts.addEmailAsync = async (userId, newEmail, verified) => {
check(userId, NonEmptyString);
check(newEmail, NonEmptyString);
check(verified, Match.Optional(Boolean));
@@ -851,9 +850,8 @@ Accounts.addEmail =
verified = false;
}
const user = await getUserById(userId, {fields: {emails: 1}});
if (!user)
throw new Meteor.Error(403, "User not found");
const user = await getUserById(userId, { fields: { emails: 1 } });
if (!user) throw new Meteor.Error(403, "User not found");
// Allow users to change their own email to a version with a different case
@@ -863,32 +861,35 @@ Accounts.addEmail =
// then we are OK and (2) if this would create a conflict with other users
// then there would already be a case-insensitive duplicate and we can't fix
// that in this code anyway.
const caseInsensitiveRegExp =
new RegExp(`^${Meteor._escapeRegExp(newEmail)}$`, 'i');
const caseInsensitiveRegExp = new RegExp(
`^${Meteor._escapeRegExp(newEmail)}$`,
"i"
);
// TODO: This is a linear search. If we have a lot of emails.
// we should consider using a different data structure.
const updatedEmail =
async (emails = [], _id) => {
let updated = false;
for (const email of emails) {
if (caseInsensitiveRegExp.test(email.address)) {
await Meteor.users.updateAsync({
_id: _id,
'emails.address': email.address
}, {
$set: {
'emails.$.address': newEmail,
'emails.$.verified': verified
}
});
updated = true;
const updatedEmail = async (emails = [], _id) => {
let updated = false;
for (const email of emails) {
if (caseInsensitiveRegExp.test(email.address)) {
await Meteor.users.updateAsync(
{
_id: _id,
"emails.address": email.address,
},
{
$set: {
"emails.$.address": newEmail,
"emails.$.verified": verified,
},
}
}
return updated;
);
updated = true;
}
const didUpdateOwnEmail =
await updatedEmail(user.emails, user._id);
}
return updated;
};
const didUpdateOwnEmail = await updatedEmail(user.emails, user._id);
// In the other updates below, we have to do another call to
// checkForCaseInsensitiveDuplicates to make sure that no conflicting values
@@ -902,32 +903,45 @@ Accounts.addEmail =
}
// Perform a case insensitive check for duplicates before update
await Accounts._checkForCaseInsensitiveDuplicates('emails.address',
'Email', newEmail, user._id);
await Accounts._checkForCaseInsensitiveDuplicates(
"emails.address",
"Email",
newEmail,
user._id
);
await Meteor.users.updateAsync({
_id: user._id
}, {
$addToSet: {
emails: {
address: newEmail,
verified: verified
}
await Meteor.users.updateAsync(
{
_id: user._id,
},
{
$addToSet: {
emails: {
address: newEmail,
verified: verified,
},
},
}
});
);
// Perform another check after update, in case a matching user has been
// inserted in the meantime
try {
await Accounts._checkForCaseInsensitiveDuplicates('emails.address',
'Email', newEmail, user._id);
await Accounts._checkForCaseInsensitiveDuplicates(
"emails.address",
"Email",
newEmail,
user._id
);
} catch (ex) {
// Undo update if the check fails
await Meteor.users.updateAsync({_id: user._id},
{$pull: {emails: {address: newEmail}}});
await Meteor.users.updateAsync(
{ _id: user._id },
{ $pull: { emails: { address: newEmail } } }
);
throw ex;
}
}
};
/**
* @summary Remove an email address asynchronously for a user. Use this instead of updating

View File

@@ -1690,10 +1690,10 @@ if (Meteor.isServer) (() => {
});
const newEmail = `${ Random.id() }@turing.com`;
await Accounts.addEmail(userId, newEmail);
await Accounts.addEmailAsync(userId, newEmail);
const thirdEmail = `${ Random.id() }@turing.com`;
await Accounts.addEmail(userId, thirdEmail, true);
await Accounts.addEmailAsync(userId, thirdEmail, true);
const u1 = await Accounts._findUserByQuery({ id: userId })
test.equal(u1.emails, [
{ address: origEmail, verified: false },
@@ -1733,7 +1733,7 @@ if (Meteor.isServer) (() => {
});
const newEmail = `${ Random.id() }@turing.com`;
await Accounts.addEmail(userId, newEmail);
await Accounts.addEmailAsync(userId, newEmail);
const u1 = await Accounts._findUserByQuery({ id: userId })
test.equal(u1.emails, [
{ address: newEmail, verified: false },
@@ -1749,10 +1749,10 @@ if (Meteor.isServer) (() => {
});
const newEmail = `${ Random.id() }@turing.com`;
await Accounts.addEmail(userId, newEmail);
await Accounts.addEmailAsync(userId, newEmail);
const thirdEmail = origEmail.toUpperCase();
await Accounts.addEmail(userId, thirdEmail, true);
await Accounts.addEmailAsync(userId, thirdEmail, true);
const u1 = await Accounts._findUserByQuery({ id: userId })
test.equal(u1.emails, [
{ address: thirdEmail, verified: true },
@@ -1775,7 +1775,7 @@ if (Meteor.isServer) (() => {
const dupEmail = user1Email.toUpperCase();
await test.throwsAsync(
async () => await Accounts.addEmail(userId2, dupEmail),
async () => await Accounts.addEmailAsync(userId2, dupEmail),
/Email already exists/
);
@@ -1797,10 +1797,10 @@ if (Meteor.isServer) (() => {
});
const newEmail = `${ Random.id() }@turing.com`;
await Accounts.addEmail(userId, newEmail);
await Accounts.addEmailAsync(userId, newEmail);
const thirdEmail = `${ Random.id() }@turing.com`;
await Accounts.addEmail(userId, thirdEmail, true);
await Accounts.addEmailAsync(userId, thirdEmail, true);
const u1 = await Accounts._findUserByQuery({ id: userId })
test.equal(u1.emails, [
{ address: origEmail, verified: false },

View File

@@ -815,7 +815,7 @@ insensitive duplicates before updates.
<ApiBox name="Accounts.setUsername" />
<ApiBox name="Accounts.addEmail" />
<ApiBox name="Accounts.addEmailAsync" />
By default, an email address is added with `{ verified: false }`. Use
[`Accounts.sendVerificationEmail`](#Accounts-sendVerificationEmail) to send an

View File

@@ -71,5 +71,29 @@ async function someFunction() {
```
## Accounts.addEmail
It is no longer available, you should use `Accounts.addEmailAsync`.
```javascript
import { Accounts } from "meteor/accounts-base";
// Before
Accounts.addEmail(
"userId",
"newEmail",
false, // this param is optional
);
// After
await Accounts.addEmailAsync(
"userId",
"newEmail",
false, // this param is optional
);
```
For a full list of changes check the [changelog](https://v3-docs.meteor.com/history.html#changelog) for Meteor v3