@unchainedshop/core-users 4.8.17 → 4.8.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ import type { MigrationRepository } from '@unchainedshop/mongodb';
2
+ export default function normalizeProfilePhone(repository: MigrationRepository): void;
@@ -0,0 +1,52 @@
1
+ import { normalizePhoneNumber } from '@unchainedshop/utils';
2
+ import { UsersCollection } from "../db/UsersCollection.js";
3
+ export default function normalizeProfilePhone(repository) {
4
+ repository?.register({
5
+ id: 20260625120200,
6
+ name: 'Normalize user.profile.phoneMobile and user.lastContact.telNumber to E.164 format',
7
+ up: async ({ logger }) => {
8
+ const Users = await UsersCollection(repository.db);
9
+ const users = await Users.find({
10
+ $or: [
11
+ { 'profile.phoneMobile': { $exists: true, $nin: [null, ''] } },
12
+ { 'lastContact.telNumber': { $exists: true, $nin: [null, ''] } },
13
+ ],
14
+ }, {
15
+ projection: {
16
+ _id: true,
17
+ profile: true,
18
+ lastContact: true,
19
+ lastBillingAddress: true,
20
+ lastLogin: true,
21
+ },
22
+ }).toArray();
23
+ let changed = 0;
24
+ let skipped = 0;
25
+ for (const user of users) {
26
+ const defaultCountry = user.lastBillingAddress?.countryCode ||
27
+ user.profile?.address?.countryCode ||
28
+ user.lastLogin?.countryCode;
29
+ const $set = {};
30
+ const phoneMobile = user.profile?.phoneMobile;
31
+ const normalizedPhoneMobile = normalizePhoneNumber(phoneMobile, defaultCountry);
32
+ if (normalizedPhoneMobile && normalizedPhoneMobile !== phoneMobile) {
33
+ $set['profile.phoneMobile'] = normalizedPhoneMobile;
34
+ }
35
+ const telNumber = user.lastContact?.telNumber;
36
+ const normalizedTelNumber = normalizePhoneNumber(telNumber, defaultCountry);
37
+ if (normalizedTelNumber && normalizedTelNumber !== telNumber) {
38
+ $set['lastContact.telNumber'] = normalizedTelNumber;
39
+ }
40
+ if (Object.keys($set).length === 0) {
41
+ if ((phoneMobile && !normalizedPhoneMobile) || (telNumber && !normalizedTelNumber)) {
42
+ skipped += 1;
43
+ }
44
+ continue;
45
+ }
46
+ await Users.updateOne({ _id: user._id }, { $set });
47
+ changed += 1;
48
+ }
49
+ logger?.info(`Normalize user phone numbers: ${changed} updated, ${skipped} left unchanged (unparseable)`);
50
+ },
51
+ });
52
+ }
@@ -2,12 +2,13 @@ import * as bcrypt from 'bcryptjs';
2
2
  import { generateDbFilterById, buildSortOptions, generateDbObjectId, insensitiveTrimmedRegexOperator, escapeRegexString, } from '@unchainedshop/mongodb';
3
3
  import { UsersCollection, } from "../db/UsersCollection.js";
4
4
  import { emit, registerEvents } from '@unchainedshop/events';
5
- import { systemLocale, SortDirection, sha256 } from '@unchainedshop/utils';
5
+ import { systemLocale, SortDirection, sha256, normalizePhoneNumber, } from '@unchainedshop/utils';
6
6
  import { UserAccountAction, userSettings, } from "../users-settings.js";
7
7
  import { configureUsersWebAuthnModule } from "./configureUsersWebAuthnModule.js";
8
8
  import * as pbkdf2 from "./pbkdf2.js";
9
9
  import { verifyWeb3Signature } from "../utils/web3-verification.js";
10
10
  import convertUserLocale from "../migrations/20241218092300-convert-locale.js";
11
+ import normalizeProfilePhone from "../migrations/20260625120200-normalize-profile-phone.js";
11
12
  const USER_EVENTS = [
12
13
  'USER_ACCOUNT_ACTION',
13
14
  'USER_CREATE',
@@ -82,6 +83,7 @@ export const buildFindSelector = ({ includeGuests, includeDeleted, queryString,
82
83
  export const configureUsersModule = async (moduleInput) => {
83
84
  const { db, options, migrationRepository } = moduleInput;
84
85
  convertUserLocale(migrationRepository);
86
+ normalizeProfilePhone(migrationRepository);
85
87
  userSettings.configureSettings(options || {}, db);
86
88
  registerEvents(USER_EVENTS);
87
89
  const Users = await UsersCollection(db);
@@ -642,11 +644,28 @@ export const configureUsersModule = async (moduleInput) => {
642
644
  return Users.findOne(userFilter, {});
643
645
  }
644
646
  const modifier = { $set: {} };
645
- if (profile) {
646
- modifier.$set = Object.keys(profile).reduce((acc, profileKey) => {
647
+ let normalizedProfile = profile;
648
+ if (profile?.phoneMobile) {
649
+ let defaultCountry = profile.address?.countryCode;
650
+ if (!defaultCountry) {
651
+ const existing = await Users.findOne(userFilter, {
652
+ projection: { lastBillingAddress: true, profile: true, lastLogin: true },
653
+ });
654
+ defaultCountry =
655
+ existing?.lastBillingAddress?.countryCode ||
656
+ existing?.profile?.address?.countryCode ||
657
+ existing?.lastLogin?.countryCode;
658
+ }
659
+ normalizedProfile = {
660
+ ...profile,
661
+ phoneMobile: normalizePhoneNumber(profile.phoneMobile, defaultCountry) || profile.phoneMobile,
662
+ };
663
+ }
664
+ if (normalizedProfile) {
665
+ modifier.$set = Object.keys(normalizedProfile).reduce((acc, profileKey) => {
647
666
  return {
648
667
  ...acc,
649
- [`profile.${profileKey}`]: profile[profileKey],
668
+ [`profile.${profileKey}`]: normalizedProfile[profileKey],
650
669
  };
651
670
  }, {});
652
671
  }
@@ -703,14 +722,23 @@ export const configureUsersModule = async (moduleInput) => {
703
722
  return null;
704
723
  const profile = user.profile || {};
705
724
  const isGuest = !!user.guest;
725
+ const defaultCountry = user.lastBillingAddress?.countryCode ||
726
+ profile.address?.countryCode ||
727
+ user.lastLogin?.countryCode;
728
+ const normalizedContact = lastContact?.telNumber
729
+ ? {
730
+ ...lastContact,
731
+ telNumber: normalizePhoneNumber(lastContact.telNumber, defaultCountry) || lastContact.telNumber,
732
+ }
733
+ : lastContact;
706
734
  const modifier = {
707
735
  $set: {
708
736
  updated: new Date(),
709
- lastContact,
737
+ lastContact: normalizedContact,
710
738
  },
711
739
  };
712
- if ((!profile.phoneMobile || isGuest) && lastContact.telNumber) {
713
- modifier.$set['profile.phoneMobile'] = lastContact.telNumber;
740
+ if ((!profile.phoneMobile || isGuest) && normalizedContact.telNumber) {
741
+ modifier.$set['profile.phoneMobile'] = normalizedContact.telNumber;
714
742
  }
715
743
  const updatedUser = await Users.findOneAndUpdate(userFilter, modifier, {
716
744
  returnDocument: 'after',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unchainedshop/core-users",
3
3
  "description": "User management module for the Unchained Engine with authentication support",
4
- "version": "4.8.17",
4
+ "version": "4.8.19",
5
5
  "main": "lib/users-index.js",
6
6
  "types": "lib/users-index.d.ts",
7
7
  "type": "module",
@@ -61,7 +61,7 @@
61
61
  "devDependencies": {
62
62
  "@noble/curves": "^2.0.0",
63
63
  "@noble/hashes": "^2.0.0",
64
- "@types/node": "^25.0.0",
64
+ "@types/node": "^26.2.0",
65
65
  "typescript": "^5.8.3"
66
66
  }
67
67
  }