appwrite-utils-cli 0.0.16 → 0.0.18
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.
- package/dist/migrations/importController.d.ts +1 -0
- package/dist/migrations/importController.js +37 -20
- package/dist/migrations/importDataActions.js +1 -1
- package/dist/migrations/users.d.ts +1 -1
- package/dist/migrations/users.js +64 -57
- package/package.json +1 -1
- package/src/migrations/importController.ts +52 -25
- package/src/migrations/importDataActions.ts +4 -1
- package/src/migrations/users.ts +89 -80
|
@@ -11,6 +11,7 @@ export declare class ImportController {
|
|
|
11
11
|
private setupOptions;
|
|
12
12
|
private documentCache;
|
|
13
13
|
private batchLimit;
|
|
14
|
+
private postImportActionsQueue;
|
|
14
15
|
constructor(config: AppwriteConfig, database: Databases, storage: Storage, appwriteFolderPath: string, importDataActions: ImportDataActions, setupOptions: SetupOptions);
|
|
15
16
|
run(): Promise<void>;
|
|
16
17
|
importCollections(db: ConfigDatabase): Promise<void>;
|
|
@@ -21,11 +21,7 @@ export class ImportController {
|
|
|
21
21
|
setupOptions;
|
|
22
22
|
documentCache;
|
|
23
23
|
batchLimit = 25; // Define batch size limit
|
|
24
|
-
|
|
25
|
-
// context: any;
|
|
26
|
-
// finalItem: any;
|
|
27
|
-
// attributeMappings: AttributeMappings;
|
|
28
|
-
// }[] = [];
|
|
24
|
+
postImportActionsQueue = [];
|
|
29
25
|
constructor(config, database, storage, appwriteFolderPath, importDataActions, setupOptions) {
|
|
30
26
|
this.config = config;
|
|
31
27
|
this.database = database;
|
|
@@ -168,6 +164,10 @@ export class ImportController {
|
|
|
168
164
|
return;
|
|
169
165
|
}
|
|
170
166
|
const user = await usersController.createUserAndReturn(userToCreate.data);
|
|
167
|
+
if (!user) {
|
|
168
|
+
logger.error(`Skipping user & contact creation for ${item} because of an error...`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
171
|
createIdToUse = user.$id;
|
|
172
172
|
context.docId = createIdToUse;
|
|
173
173
|
context = { ...context, ...user };
|
|
@@ -207,19 +207,23 @@ export class ImportController {
|
|
|
207
207
|
const attributeMappingsWithActions = this.getAttributeMappingsWithActions(importDef.attributeMappings, afterImportActionContext, finalItem);
|
|
208
208
|
if (attributeMappingsWithActions.some((m) => m.postImportActions)) {
|
|
209
209
|
logger.info(`Pushing to post-import actions queue for ${context.docId}`);
|
|
210
|
-
const afterImportOperationContext = ContextObject.parse({
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
finalItem: finalItem,
|
|
214
|
-
attributeMappings: attributeMappingsWithActions,
|
|
215
|
-
context: afterImportActionContext,
|
|
216
|
-
});
|
|
217
|
-
await createOrFindAfterImportOperation(this.database, context.collId, afterImportOperationContext);
|
|
218
|
-
// this.postImportActionsQueue.push({
|
|
219
|
-
// context: afterImportActionContext,
|
|
210
|
+
// const afterImportOperationContext = ContextObject.parse({
|
|
211
|
+
// dbId: db.$id,
|
|
212
|
+
// collectionId: collection.$id,
|
|
220
213
|
// finalItem: finalItem,
|
|
221
214
|
// attributeMappings: attributeMappingsWithActions,
|
|
215
|
+
// context: afterImportActionContext,
|
|
222
216
|
// });
|
|
217
|
+
// await createOrFindAfterImportOperation(
|
|
218
|
+
// this.database,
|
|
219
|
+
// context.collId,
|
|
220
|
+
// afterImportOperationContext
|
|
221
|
+
// );
|
|
222
|
+
this.postImportActionsQueue.push({
|
|
223
|
+
context: afterImportActionContext,
|
|
224
|
+
finalItem: finalItem,
|
|
225
|
+
attributeMappings: attributeMappingsWithActions,
|
|
226
|
+
});
|
|
223
227
|
}
|
|
224
228
|
}));
|
|
225
229
|
results.forEach((result) => {
|
|
@@ -314,16 +318,29 @@ export class ImportController {
|
|
|
314
318
|
});
|
|
315
319
|
}
|
|
316
320
|
async executePostImportActions(dbId) {
|
|
317
|
-
|
|
318
|
-
for (const
|
|
319
|
-
|
|
321
|
+
let actionQueue = [];
|
|
322
|
+
for (const action of this.postImportActionsQueue) {
|
|
323
|
+
actionQueue.push(this.importDataActions.executeAfterImportActions(action.finalItem, action.attributeMappings, action.context));
|
|
320
324
|
}
|
|
321
|
-
const results = await Promise.allSettled(
|
|
325
|
+
const results = await Promise.allSettled(actionQueue);
|
|
322
326
|
results.forEach((result) => {
|
|
323
327
|
if (result.status === "rejected") {
|
|
324
|
-
console.error("
|
|
328
|
+
console.error("An action promise was rejected:", result.reason);
|
|
329
|
+
logger.error(`An action promise was rejected: ${result.reason} -- ${JSON.stringify(result)}`);
|
|
325
330
|
}
|
|
326
331
|
});
|
|
332
|
+
// const collectionActionsPromises = [];
|
|
333
|
+
// for (const collection of this.config.collections) {
|
|
334
|
+
// collectionActionsPromises.push(
|
|
335
|
+
// this.executeActionsInParallel(dbId, collection)
|
|
336
|
+
// );
|
|
337
|
+
// }
|
|
338
|
+
// const results = await Promise.allSettled(collectionActionsPromises);
|
|
339
|
+
// results.forEach((result) => {
|
|
340
|
+
// if (result.status === "rejected") {
|
|
341
|
+
// console.error("A process batch promise was rejected:", result.reason);
|
|
342
|
+
// }
|
|
343
|
+
// });
|
|
327
344
|
}
|
|
328
345
|
async executeActionsInParallel(dbId, collection) {
|
|
329
346
|
const collectionExists = await checkForCollection(this.database, dbId, collection);
|
|
@@ -193,7 +193,7 @@ export class ImportDataActions {
|
|
|
193
193
|
resolvedString = resolvedString.replace(match[0], value);
|
|
194
194
|
}
|
|
195
195
|
else {
|
|
196
|
-
logger.warn(`Failed to resolve ${template} in context: `, context);
|
|
196
|
+
logger.warn(`Failed to resolve ${template} in context: `, JSON.stringify({ ...context, ...item }, null, 2));
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
// console.log(`Resolved string: ${resolvedString}`);
|
|
@@ -7,5 +7,5 @@ export declare class UsersController {
|
|
|
7
7
|
static userFields: string[];
|
|
8
8
|
constructor(config: AppwriteConfig, db: Databases);
|
|
9
9
|
wipeUsers(): Promise<void>;
|
|
10
|
-
createUserAndReturn(item: AuthUserCreate): Promise<Models.User<Models.Preferences
|
|
10
|
+
createUserAndReturn(item: AuthUserCreate): Promise<Models.User<Models.Preferences> | undefined>;
|
|
11
11
|
}
|
package/dist/migrations/users.js
CHANGED
|
@@ -40,72 +40,79 @@ export class UsersController {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
async createUserAndReturn(item) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
foundUsers = foundUsersByEmail.users;
|
|
50
|
-
}
|
|
51
|
-
if (item.phone) {
|
|
52
|
-
const foundUsersByPhone = await this.users.list([
|
|
53
|
-
Query.equal("phone", item.phone),
|
|
54
|
-
]);
|
|
55
|
-
foundUsers = foundUsers.length
|
|
56
|
-
? foundUsers.concat(foundUsersByPhone.users)
|
|
57
|
-
: foundUsersByPhone.users;
|
|
58
|
-
}
|
|
59
|
-
let userToReturn = foundUsers[0] || undefined;
|
|
60
|
-
if (!userToReturn) {
|
|
61
|
-
userToReturn = await this.users.create(item.userId || ID.unique(), item.email || undefined, item.phone && item.phone.length < 15 && item.phone.startsWith("+")
|
|
62
|
-
? item.phone
|
|
63
|
-
: undefined, item.password?.toLowerCase() || `changeMe${item.email}`.toLowerCase(), item.name || undefined);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
// Update user details as necessary, ensuring email uniqueness if attempting an update.
|
|
67
|
-
if (item.email &&
|
|
68
|
-
item.email !== userToReturn.email &&
|
|
69
|
-
!_.isEmpty(item.email) &&
|
|
70
|
-
!_.isUndefined(item.email)) {
|
|
71
|
-
const emailExists = await this.users.list([
|
|
43
|
+
let userToReturn = undefined;
|
|
44
|
+
try {
|
|
45
|
+
// Attempt to find an existing user by email or phone.
|
|
46
|
+
let foundUsers = [];
|
|
47
|
+
if (item.email) {
|
|
48
|
+
const foundUsersByEmail = await this.users.list([
|
|
72
49
|
Query.equal("email", item.email),
|
|
73
50
|
]);
|
|
74
|
-
|
|
75
|
-
|
|
51
|
+
foundUsers = foundUsersByEmail.users;
|
|
52
|
+
}
|
|
53
|
+
if (item.phone) {
|
|
54
|
+
const foundUsersByPhone = await this.users.list([
|
|
55
|
+
Query.equal("phone", item.phone),
|
|
56
|
+
]);
|
|
57
|
+
foundUsers = foundUsers.length
|
|
58
|
+
? foundUsers.concat(foundUsersByPhone.users)
|
|
59
|
+
: foundUsersByPhone.users;
|
|
60
|
+
}
|
|
61
|
+
userToReturn = foundUsers[0] || undefined;
|
|
62
|
+
if (!userToReturn) {
|
|
63
|
+
userToReturn = await this.users.create(item.userId || ID.unique(), item.email || undefined, item.phone && item.phone.length < 15 && item.phone.startsWith("+")
|
|
64
|
+
? item.phone
|
|
65
|
+
: undefined, item.password?.toLowerCase() || `changeMe${item.email}`.toLowerCase(), item.name || undefined);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Update user details as necessary, ensuring email uniqueness if attempting an update.
|
|
69
|
+
if (item.email &&
|
|
70
|
+
item.email !== userToReturn.email &&
|
|
71
|
+
!_.isEmpty(item.email) &&
|
|
72
|
+
!_.isUndefined(item.email)) {
|
|
73
|
+
const emailExists = await this.users.list([
|
|
74
|
+
Query.equal("email", item.email),
|
|
75
|
+
]);
|
|
76
|
+
if (emailExists.users.length === 0) {
|
|
77
|
+
userToReturn = await this.users.updateEmail(userToReturn.$id, item.email);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log("Email update skipped: Email already exists.");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (item.password) {
|
|
84
|
+
userToReturn = await this.users.updatePassword(userToReturn.$id, item.password.toLowerCase());
|
|
76
85
|
}
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
if (item.name && item.name !== userToReturn.name) {
|
|
87
|
+
userToReturn = await this.users.updateName(userToReturn.$id, item.name);
|
|
88
|
+
}
|
|
89
|
+
if (item.phone &&
|
|
90
|
+
item.phone !== userToReturn.phone &&
|
|
91
|
+
item.phone.length < 15 &&
|
|
92
|
+
item.phone.startsWith("+") &&
|
|
93
|
+
(_.isUndefined(userToReturn.phone) || _.isEmpty(userToReturn.phone))) {
|
|
94
|
+
const userFoundWithPhone = await this.users.list([
|
|
95
|
+
Query.equal("phone", item.phone),
|
|
96
|
+
]);
|
|
97
|
+
if (userFoundWithPhone.total === 0) {
|
|
98
|
+
userToReturn = await this.users.updatePhone(userToReturn.$id, item.phone);
|
|
99
|
+
}
|
|
79
100
|
}
|
|
80
101
|
}
|
|
81
|
-
if (item
|
|
82
|
-
|
|
102
|
+
if (item.$createdAt && item.$updatedAt) {
|
|
103
|
+
console.log("$createdAt and $updatedAt are not yet supported, sorry about that!");
|
|
83
104
|
}
|
|
84
|
-
if (item.
|
|
85
|
-
userToReturn = await this.users.
|
|
105
|
+
if (item.labels && item.labels.length) {
|
|
106
|
+
userToReturn = await this.users.updateLabels(userToReturn.$id, item.labels);
|
|
86
107
|
}
|
|
87
|
-
if (item.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
item.phone.startsWith("+") &&
|
|
91
|
-
(_.isUndefined(userToReturn.phone) || _.isEmpty(userToReturn.phone))) {
|
|
92
|
-
const userFoundWithPhone = await this.users.list([
|
|
93
|
-
Query.equal("phone", item.phone),
|
|
94
|
-
]);
|
|
95
|
-
if (userFoundWithPhone.total === 0) {
|
|
96
|
-
userToReturn = await this.users.updatePhone(userToReturn.$id, item.phone);
|
|
97
|
-
}
|
|
108
|
+
if (item.prefs && Object.keys(item.prefs).length) {
|
|
109
|
+
await this.users.updatePrefs(userToReturn.$id, item.prefs);
|
|
110
|
+
userToReturn.prefs = item.prefs;
|
|
98
111
|
}
|
|
112
|
+
return userToReturn;
|
|
99
113
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
if (item.labels && item.labels.length) {
|
|
104
|
-
userToReturn = await this.users.updateLabels(userToReturn.$id, item.labels);
|
|
105
|
-
}
|
|
106
|
-
if (item.prefs && Object.keys(item.prefs).length) {
|
|
107
|
-
userToReturn = await this.users.updatePrefs(userToReturn.$id, item.prefs);
|
|
114
|
+
catch (error) {
|
|
115
|
+
return userToReturn;
|
|
108
116
|
}
|
|
109
|
-
return userToReturn;
|
|
110
117
|
}
|
|
111
118
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appwrite-utils-cli",
|
|
3
3
|
"description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.18",
|
|
5
5
|
"main": "src/main.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -47,11 +47,11 @@ export class ImportController {
|
|
|
47
47
|
private setupOptions: SetupOptions;
|
|
48
48
|
private documentCache: Map<string, any>;
|
|
49
49
|
private batchLimit: number = 25; // Define batch size limit
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
private postImportActionsQueue: {
|
|
51
|
+
context: any;
|
|
52
|
+
finalItem: any;
|
|
53
|
+
attributeMappings: AttributeMappings;
|
|
54
|
+
}[] = [];
|
|
55
55
|
|
|
56
56
|
constructor(
|
|
57
57
|
config: AppwriteConfig,
|
|
@@ -284,6 +284,12 @@ export class ImportController {
|
|
|
284
284
|
const user = await usersController.createUserAndReturn(
|
|
285
285
|
userToCreate.data
|
|
286
286
|
);
|
|
287
|
+
if (!user) {
|
|
288
|
+
logger.error(
|
|
289
|
+
`Skipping user & contact creation for ${item} because of an error...`
|
|
290
|
+
);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
287
293
|
createIdToUse = user.$id;
|
|
288
294
|
context.docId = createIdToUse;
|
|
289
295
|
context = { ...context, ...user };
|
|
@@ -351,23 +357,23 @@ export class ImportController {
|
|
|
351
357
|
logger.info(
|
|
352
358
|
`Pushing to post-import actions queue for ${context.docId}`
|
|
353
359
|
);
|
|
354
|
-
const afterImportOperationContext = ContextObject.parse({
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
finalItem: finalItem,
|
|
358
|
-
attributeMappings: attributeMappingsWithActions,
|
|
359
|
-
context: afterImportActionContext,
|
|
360
|
-
});
|
|
361
|
-
await createOrFindAfterImportOperation(
|
|
362
|
-
this.database,
|
|
363
|
-
context.collId,
|
|
364
|
-
afterImportOperationContext
|
|
365
|
-
);
|
|
366
|
-
// this.postImportActionsQueue.push({
|
|
367
|
-
// context: afterImportActionContext,
|
|
360
|
+
// const afterImportOperationContext = ContextObject.parse({
|
|
361
|
+
// dbId: db.$id,
|
|
362
|
+
// collectionId: collection.$id,
|
|
368
363
|
// finalItem: finalItem,
|
|
369
364
|
// attributeMappings: attributeMappingsWithActions,
|
|
365
|
+
// context: afterImportActionContext,
|
|
370
366
|
// });
|
|
367
|
+
// await createOrFindAfterImportOperation(
|
|
368
|
+
// this.database,
|
|
369
|
+
// context.collId,
|
|
370
|
+
// afterImportOperationContext
|
|
371
|
+
// );
|
|
372
|
+
this.postImportActionsQueue.push({
|
|
373
|
+
context: afterImportActionContext,
|
|
374
|
+
finalItem: finalItem,
|
|
375
|
+
attributeMappings: attributeMappingsWithActions,
|
|
376
|
+
});
|
|
371
377
|
}
|
|
372
378
|
})
|
|
373
379
|
);
|
|
@@ -506,18 +512,39 @@ export class ImportController {
|
|
|
506
512
|
}
|
|
507
513
|
|
|
508
514
|
async executePostImportActions(dbId: string) {
|
|
509
|
-
|
|
510
|
-
for (const
|
|
511
|
-
|
|
512
|
-
this.
|
|
515
|
+
let actionQueue: Promise<any>[] = [];
|
|
516
|
+
for (const action of this.postImportActionsQueue) {
|
|
517
|
+
actionQueue.push(
|
|
518
|
+
this.importDataActions.executeAfterImportActions(
|
|
519
|
+
action.finalItem,
|
|
520
|
+
action.attributeMappings,
|
|
521
|
+
action.context
|
|
522
|
+
)
|
|
513
523
|
);
|
|
514
524
|
}
|
|
515
|
-
const results = await Promise.allSettled(
|
|
525
|
+
const results = await Promise.allSettled(actionQueue);
|
|
516
526
|
results.forEach((result) => {
|
|
517
527
|
if (result.status === "rejected") {
|
|
518
|
-
console.error("
|
|
528
|
+
console.error("An action promise was rejected:", result.reason);
|
|
529
|
+
logger.error(
|
|
530
|
+
`An action promise was rejected: ${result.reason} -- ${JSON.stringify(
|
|
531
|
+
result
|
|
532
|
+
)}`
|
|
533
|
+
);
|
|
519
534
|
}
|
|
520
535
|
});
|
|
536
|
+
// const collectionActionsPromises = [];
|
|
537
|
+
// for (const collection of this.config.collections) {
|
|
538
|
+
// collectionActionsPromises.push(
|
|
539
|
+
// this.executeActionsInParallel(dbId, collection)
|
|
540
|
+
// );
|
|
541
|
+
// }
|
|
542
|
+
// const results = await Promise.allSettled(collectionActionsPromises);
|
|
543
|
+
// results.forEach((result) => {
|
|
544
|
+
// if (result.status === "rejected") {
|
|
545
|
+
// console.error("A process batch promise was rejected:", result.reason);
|
|
546
|
+
// }
|
|
547
|
+
// });
|
|
521
548
|
}
|
|
522
549
|
|
|
523
550
|
async executeActionsInParallel(dbId: string, collection: ConfigCollection) {
|
|
@@ -285,7 +285,10 @@ export class ImportDataActions {
|
|
|
285
285
|
: resolvedValue;
|
|
286
286
|
resolvedString = resolvedString.replace(match[0], value);
|
|
287
287
|
} else {
|
|
288
|
-
logger.warn(
|
|
288
|
+
logger.warn(
|
|
289
|
+
`Failed to resolve ${template} in context: `,
|
|
290
|
+
JSON.stringify({ ...context, ...item }, null, 2)
|
|
291
|
+
);
|
|
289
292
|
}
|
|
290
293
|
}
|
|
291
294
|
// console.log(`Resolved string: ${resolvedString}`);
|
package/src/migrations/users.ts
CHANGED
|
@@ -49,96 +49,105 @@ export class UsersController {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async createUserAndReturn(item: AuthUserCreate) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
foundUsers = foundUsersByEmail.users;
|
|
59
|
-
}
|
|
60
|
-
if (item.phone) {
|
|
61
|
-
const foundUsersByPhone = await this.users.list([
|
|
62
|
-
Query.equal("phone", item.phone),
|
|
63
|
-
]);
|
|
64
|
-
foundUsers = foundUsers.length
|
|
65
|
-
? foundUsers.concat(foundUsersByPhone.users)
|
|
66
|
-
: foundUsersByPhone.users;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let userToReturn = foundUsers[0] || undefined;
|
|
70
|
-
|
|
71
|
-
if (!userToReturn) {
|
|
72
|
-
userToReturn = await this.users.create(
|
|
73
|
-
item.userId || ID.unique(),
|
|
74
|
-
item.email || undefined,
|
|
75
|
-
item.phone && item.phone.length < 15 && item.phone.startsWith("+")
|
|
76
|
-
? item.phone
|
|
77
|
-
: undefined,
|
|
78
|
-
item.password?.toLowerCase() || `changeMe${item.email}`.toLowerCase(),
|
|
79
|
-
item.name || undefined
|
|
80
|
-
);
|
|
81
|
-
} else {
|
|
82
|
-
// Update user details as necessary, ensuring email uniqueness if attempting an update.
|
|
83
|
-
if (
|
|
84
|
-
item.email &&
|
|
85
|
-
item.email !== userToReturn.email &&
|
|
86
|
-
!_.isEmpty(item.email) &&
|
|
87
|
-
!_.isUndefined(item.email)
|
|
88
|
-
) {
|
|
89
|
-
const emailExists = await this.users.list([
|
|
52
|
+
let userToReturn: Models.User<Models.Preferences> | undefined = undefined;
|
|
53
|
+
try {
|
|
54
|
+
// Attempt to find an existing user by email or phone.
|
|
55
|
+
let foundUsers: Models.User<Models.Preferences>[] = [];
|
|
56
|
+
if (item.email) {
|
|
57
|
+
const foundUsersByEmail = await this.users.list([
|
|
90
58
|
Query.equal("email", item.email),
|
|
91
59
|
]);
|
|
92
|
-
|
|
93
|
-
|
|
60
|
+
foundUsers = foundUsersByEmail.users;
|
|
61
|
+
}
|
|
62
|
+
if (item.phone) {
|
|
63
|
+
const foundUsersByPhone = await this.users.list([
|
|
64
|
+
Query.equal("phone", item.phone),
|
|
65
|
+
]);
|
|
66
|
+
foundUsers = foundUsers.length
|
|
67
|
+
? foundUsers.concat(foundUsersByPhone.users)
|
|
68
|
+
: foundUsersByPhone.users;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
userToReturn = foundUsers[0] || undefined;
|
|
72
|
+
|
|
73
|
+
if (!userToReturn) {
|
|
74
|
+
userToReturn = await this.users.create(
|
|
75
|
+
item.userId || ID.unique(),
|
|
76
|
+
item.email || undefined,
|
|
77
|
+
item.phone && item.phone.length < 15 && item.phone.startsWith("+")
|
|
78
|
+
? item.phone
|
|
79
|
+
: undefined,
|
|
80
|
+
item.password?.toLowerCase() || `changeMe${item.email}`.toLowerCase(),
|
|
81
|
+
item.name || undefined
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
// Update user details as necessary, ensuring email uniqueness if attempting an update.
|
|
85
|
+
if (
|
|
86
|
+
item.email &&
|
|
87
|
+
item.email !== userToReturn.email &&
|
|
88
|
+
!_.isEmpty(item.email) &&
|
|
89
|
+
!_.isUndefined(item.email)
|
|
90
|
+
) {
|
|
91
|
+
const emailExists = await this.users.list([
|
|
92
|
+
Query.equal("email", item.email),
|
|
93
|
+
]);
|
|
94
|
+
if (emailExists.users.length === 0) {
|
|
95
|
+
userToReturn = await this.users.updateEmail(
|
|
96
|
+
userToReturn.$id,
|
|
97
|
+
item.email
|
|
98
|
+
);
|
|
99
|
+
} else {
|
|
100
|
+
console.log("Email update skipped: Email already exists.");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (item.password) {
|
|
104
|
+
userToReturn = await this.users.updatePassword(
|
|
94
105
|
userToReturn.$id,
|
|
95
|
-
item.
|
|
106
|
+
item.password.toLowerCase()
|
|
96
107
|
);
|
|
97
|
-
}
|
|
98
|
-
|
|
108
|
+
}
|
|
109
|
+
if (item.name && item.name !== userToReturn.name) {
|
|
110
|
+
userToReturn = await this.users.updateName(
|
|
111
|
+
userToReturn.$id,
|
|
112
|
+
item.name
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (
|
|
116
|
+
item.phone &&
|
|
117
|
+
item.phone !== userToReturn.phone &&
|
|
118
|
+
item.phone.length < 15 &&
|
|
119
|
+
item.phone.startsWith("+") &&
|
|
120
|
+
(_.isUndefined(userToReturn.phone) || _.isEmpty(userToReturn.phone))
|
|
121
|
+
) {
|
|
122
|
+
const userFoundWithPhone = await this.users.list([
|
|
123
|
+
Query.equal("phone", item.phone),
|
|
124
|
+
]);
|
|
125
|
+
if (userFoundWithPhone.total === 0) {
|
|
126
|
+
userToReturn = await this.users.updatePhone(
|
|
127
|
+
userToReturn.$id,
|
|
128
|
+
item.phone
|
|
129
|
+
);
|
|
130
|
+
}
|
|
99
131
|
}
|
|
100
132
|
}
|
|
101
|
-
if (item
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
item.password.toLowerCase()
|
|
133
|
+
if (item.$createdAt && item.$updatedAt) {
|
|
134
|
+
console.log(
|
|
135
|
+
"$createdAt and $updatedAt are not yet supported, sorry about that!"
|
|
105
136
|
);
|
|
106
137
|
}
|
|
107
|
-
if (item.
|
|
108
|
-
userToReturn = await this.users.
|
|
138
|
+
if (item.labels && item.labels.length) {
|
|
139
|
+
userToReturn = await this.users.updateLabels(
|
|
140
|
+
userToReturn.$id,
|
|
141
|
+
item.labels
|
|
142
|
+
);
|
|
109
143
|
}
|
|
110
|
-
if (
|
|
111
|
-
item.
|
|
112
|
-
|
|
113
|
-
item.phone.length < 15 &&
|
|
114
|
-
item.phone.startsWith("+") &&
|
|
115
|
-
(_.isUndefined(userToReturn.phone) || _.isEmpty(userToReturn.phone))
|
|
116
|
-
) {
|
|
117
|
-
const userFoundWithPhone = await this.users.list([
|
|
118
|
-
Query.equal("phone", item.phone),
|
|
119
|
-
]);
|
|
120
|
-
if (userFoundWithPhone.total === 0) {
|
|
121
|
-
userToReturn = await this.users.updatePhone(
|
|
122
|
-
userToReturn.$id,
|
|
123
|
-
item.phone
|
|
124
|
-
);
|
|
125
|
-
}
|
|
144
|
+
if (item.prefs && Object.keys(item.prefs).length) {
|
|
145
|
+
await this.users.updatePrefs(userToReturn.$id, item.prefs);
|
|
146
|
+
userToReturn.prefs = item.prefs;
|
|
126
147
|
}
|
|
148
|
+
return userToReturn;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return userToReturn;
|
|
127
151
|
}
|
|
128
|
-
if (item.$createdAt && item.$updatedAt) {
|
|
129
|
-
console.log(
|
|
130
|
-
"$createdAt and $updatedAt are not yet supported, sorry about that!"
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
if (item.labels && item.labels.length) {
|
|
134
|
-
userToReturn = await this.users.updateLabels(
|
|
135
|
-
userToReturn.$id,
|
|
136
|
-
item.labels
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
if (item.prefs && Object.keys(item.prefs).length) {
|
|
140
|
-
userToReturn = await this.users.updatePrefs(userToReturn.$id, item.prefs);
|
|
141
|
-
}
|
|
142
|
-
return userToReturn;
|
|
143
152
|
}
|
|
144
153
|
}
|