Merge pull request #13677 from harryadel/feature/add-replace-email-utility

Add Accounts.replaceEmailAsync
This commit is contained in:
Nacho Codoñer
2025-04-14 13:34:24 +02:00
committed by GitHub
8 changed files with 79 additions and 1 deletions

View File

@@ -213,6 +213,7 @@ redirects:
/#/full/accounts-setusername: 'api/passwords.html#accounts-setusername'
/#/full/accounts-addemail: 'api/passwords.html#accounts-addemail'
/#/full/accounts-removeemail: 'api/passwords.html#accounts-removeemail'
/#/full/accounts_replaceemail: 'api/passwords.html#Accounts-replaceEmail'
/#/full/accounts_verifyemail: 'api/passwords.html#Accounts-verifyEmail'
/#/full/accounts-finduserbyusername: 'api/passwords.html#accounts-finduserbyusername'
/#/full/accounts-finduserbyemail: 'api/passwords.html#accounts-finduserbyemail'

View File

@@ -55,6 +55,7 @@
- `Accounts.sendVerificationEmail`
- `Accounts.addEmail`
- `Accounts.removeEmail`
- `Accounts.replaceEmailAsync`
- `Accounts.verifyEmail`
- `Accounts.createUserVerifyingEmail`
- `Accounts.createUser`

View File

@@ -59,6 +59,8 @@ By default, an email address is added with `{ verified: false }`. Use
[`Accounts.sendVerificationEmail`](#Accounts-sendVerificationEmail) to send an
email with a link the user can use to verify their email address.
{% apibox "Accounts.replaceEmailAsync" %}
{% apibox "Accounts.removeEmail" %}
{% apibox "Accounts.verifyEmail" %}

View File

@@ -188,6 +188,8 @@ export namespace Accounts {
function removeEmail(userId: string, email: string): Promise<void>;
function replaceEmailAsync(userId: string, oldEmail: string, newEmail: string, verified?: boolean): Promise<void>;
function onCreateUser(
func: (options: { profile?: {} | undefined }, user: Meteor.User) => void
): void;

View File

@@ -1022,6 +1022,52 @@ Meteor.methods(
}
});
/**
* @summary Asynchronously replace 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.
* @locus Server
* @param {String} userId The ID of the user to update.
* @param {String} oldEmail The email address to replace.
* @param {String} newEmail The new email address to use.
* @param {Boolean} [verified] Optional - whether the new email address should
* be marked as verified. Defaults to false.
* @importFromPackage accounts-base
*/
Accounts.replaceEmailAsync = async (userId, oldEmail, newEmail, verified) => {
check(userId, NonEmptyString);
check(oldEmail, NonEmptyString);
check(newEmail, NonEmptyString);
check(verified, Match.Optional(Boolean));
if (verified === void 0) {
verified = false;
}
const user = await getUserById(userId, { fields: { _id: 1 } });
if (!user)
throw new Meteor.Error(403, "User not found");
// Ensure no user already has this new email
await Accounts._checkForCaseInsensitiveDuplicates(
"emails.address",
"Email",
newEmail,
user._id
);
const result = await Meteor.users.updateAsync(
{ _id: user._id, 'emails.address': oldEmail },
{ $set: { 'emails.$.address': newEmail, 'emails.$.verified': verified } }
);
if (result.modifiedCount === 0) {
throw new Meteor.Error(404, "No user could be found with old email");
}
};
/**
* @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

View File

@@ -1789,7 +1789,30 @@ if (Meteor.isServer) (() => {
]);
});
Tinytest.addAsync("passwords - remove email",
Tinytest.addAsync("accounts emails - replace email", async test => {
const origEmail = `originalemail@test.com`;
const userId = await Accounts.createUserAsync({
email: origEmail,
password: 'password'
});
const newEmail = `newemail@test.com`;
const u1 = await Accounts._findUserByQuery({ id: userId })
test.equal(u1.emails, [
{ address: origEmail, verified: false }
]);
await Accounts.replaceEmailAsync(userId, origEmail, newEmail);
const u2 = await Accounts._findUserByQuery({ id: userId })
test.equal(u2.emails, [
{ address: newEmail, verified: false }
]);
})
Tinytest.addAsync("passwords - remove email",
async test => {
const origEmail = `${ Random.id() }@turing.com`;
const userId = await Accounts.createUser({

View File

@@ -888,6 +888,8 @@ email with a link the user can use to verify their email address.
<ApiBox name="Accounts.removeEmail" />
<ApiBox name="Accounts.replaceEmailAsync" />
<ApiBox name="Accounts.verifyEmail" />
If the user trying to verify the email has 2FA enabled, this error will be thrown:

View File

@@ -58,6 +58,7 @@
- `Accounts.sendVerificationEmail`
- `Accounts.addEmail`
- `Accounts.removeEmail`
- `Accounts.replaceEmailAsync`
- `Accounts.verifyEmail`
- `Accounts.createUserVerifyingEmail`
- `Accounts.createUser`