@edgedev/firebase 1.8.12 → 1.9.2
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/README.md +60 -0
- package/edgeFirebase.ts +62 -15
- package/package.json +1 -1
- package/src/functions.js +50 -0
package/README.md
CHANGED
|
@@ -239,6 +239,63 @@ Calling this will generate a Microsoft Sign In Popup and register the user using
|
|
|
239
239
|
);
|
|
240
240
|
```
|
|
241
241
|
|
|
242
|
+
### Inviting an Existing User to Register with a New Organization or Member
|
|
243
|
+
|
|
244
|
+
To invite an existing user to register with a new organization or member's data and get the corresponding roles, use the `edgeFirebase.currentUserRegister(userRegister)` method.
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
const userRegisterData = {
|
|
248
|
+
registrationCode: "12345",
|
|
249
|
+
dynamicDocumentFieldValue: "fieldName",
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const response = await edgeFirebase.currentUserRegister(userRegisterData);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### Parameters
|
|
256
|
+
|
|
257
|
+
- `userRegister` (object): An object containing the user registration data. It must include a `registrationCode` property provided by the inviting organization or member. It can also include a `dynamicDocumentFieldValue` property, which is a single string representing the name of an additional data field for registration.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
interface userRegister {
|
|
261
|
+
registrationCode: string;
|
|
262
|
+
dynamicDocumentFieldValue?: string;
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Returns
|
|
267
|
+
|
|
268
|
+
The method returns a Promise that resolves to an `actionResponse` object:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
interface actionResponse {
|
|
272
|
+
success: boolean;
|
|
273
|
+
message: string;
|
|
274
|
+
meta: {};
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Example usage:
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
<script setup>
|
|
282
|
+
async function inviteExistingUser() {
|
|
283
|
+
const userRegisterData = {
|
|
284
|
+
registrationCode: "12345",
|
|
285
|
+
dynamicDocumentFieldValue: "fieldName",
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const response = await edgeFirebase.currentUserRegister(userRegisterData);
|
|
289
|
+
if (response.success) {
|
|
290
|
+
console.log("Existing user invited and registered successfully");
|
|
291
|
+
} else {
|
|
292
|
+
console.error("Error inviting and registering existing user:", response.message);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
</script>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
|
|
242
299
|
### Explanation of permissions
|
|
243
300
|
|
|
244
301
|
- **assign: boolean** - When a user has this permission for a collection they can assign other users to the collection and change permissions for that collection. For a user to be able run setUser, storeCollectionPermisions, storeUserRoles, removeUserRoles, storeUserSpecialPermissions, or removeUserSpecialPermissions, they must have assign access to any of the collection paths passed into those functions.
|
|
@@ -475,6 +532,7 @@ interface UserDataObject {
|
|
|
475
532
|
firebaseUser: object; // contains the entire auth from firebase
|
|
476
533
|
oAuthCredential: object; // contains oAuth ID and token information
|
|
477
534
|
loggedIn: boolean;
|
|
535
|
+
loggingIn: boolean: // true while logging in used for loading screens
|
|
478
536
|
logInError: boolean;
|
|
479
537
|
logInErrorMessage: string;
|
|
480
538
|
meta: object;
|
|
@@ -502,6 +560,8 @@ interface permissions {
|
|
|
502
560
|
```
|
|
503
561
|
The reactive item **edgeFirebase.user.loggedIn** can be used in code or templates to determine if the user is logged in.
|
|
504
562
|
|
|
563
|
+
**edgeFirebase.user.logginIn** is true while the user is logging in. This can be used to show a loading screen.
|
|
564
|
+
|
|
505
565
|
If there is an error logging in, **edgeFirebase.user.logInError** will be true and **edgeFirebase.user.logInErrorMessage** can be used to return that error to the user.
|
|
506
566
|
|
|
507
567
|
After logging in, **edgeFirebase.logOut** becomes available. Logging out will also automatically disconnect all FireStore listeners.
|
package/edgeFirebase.ts
CHANGED
|
@@ -103,6 +103,7 @@ interface UserDataObject {
|
|
|
103
103
|
firebaseUser: object;
|
|
104
104
|
oAuthCredential: { accessToken: string; idToken: string;}
|
|
105
105
|
loggedIn: boolean;
|
|
106
|
+
loggingIn: boolean;
|
|
106
107
|
logInError: boolean;
|
|
107
108
|
logInErrorMessage: string;
|
|
108
109
|
meta: object;
|
|
@@ -126,6 +127,7 @@ interface newUser {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
interface userRegister {
|
|
130
|
+
uid?: string;
|
|
129
131
|
email?: string;
|
|
130
132
|
password?: string;
|
|
131
133
|
meta: object;
|
|
@@ -233,7 +235,7 @@ export const EdgeFirebase = class {
|
|
|
233
235
|
|
|
234
236
|
private functions = null;
|
|
235
237
|
|
|
236
|
-
public runFunction = async (functionName: string, data:
|
|
238
|
+
public runFunction = async (functionName: string, data: Record<string, unknown>) => {
|
|
237
239
|
data.uid = this.user.uid;
|
|
238
240
|
const callable = httpsCallable(this.functions, functionName);
|
|
239
241
|
return await callable(data);
|
|
@@ -387,6 +389,7 @@ export const EdgeFirebase = class {
|
|
|
387
389
|
await this.startCollectionPermissionsSync()
|
|
388
390
|
await this.initUserMetaPermissions(docSnap);
|
|
389
391
|
this.user.loggedIn = true;
|
|
392
|
+
this.user.loggingIn = false;
|
|
390
393
|
};
|
|
391
394
|
|
|
392
395
|
private waitForUser = async(): Promise<void> => {
|
|
@@ -405,6 +408,7 @@ export const EdgeFirebase = class {
|
|
|
405
408
|
private setOnAuthStateChanged = (): void => {
|
|
406
409
|
onAuthStateChanged(this.auth, (userAuth) => {
|
|
407
410
|
if (userAuth) {
|
|
411
|
+
this.user.loggingIn = true;
|
|
408
412
|
this.user.email = userAuth.email;
|
|
409
413
|
this.user.uid = userAuth.uid;
|
|
410
414
|
this.user.firebaseUser = userAuth;
|
|
@@ -419,6 +423,7 @@ export const EdgeFirebase = class {
|
|
|
419
423
|
this.user.oAuthCredential.accessToken = "";
|
|
420
424
|
this.user.oAuthCredential.idToken = "";
|
|
421
425
|
this.user.loggedIn = false;
|
|
426
|
+
this.user.loggingIn = false;
|
|
422
427
|
}
|
|
423
428
|
});
|
|
424
429
|
};
|
|
@@ -462,6 +467,32 @@ export const EdgeFirebase = class {
|
|
|
462
467
|
}
|
|
463
468
|
}
|
|
464
469
|
|
|
470
|
+
public currentUserRegister = async (userRegister: userRegister): Promise<actionResponse> => {
|
|
471
|
+
if (!Object.prototype.hasOwnProperty.call(userRegister, 'registrationCode') || userRegister.registrationCode === "") {
|
|
472
|
+
return this.sendResponse({
|
|
473
|
+
success: false,
|
|
474
|
+
message: "Registration code is required.",
|
|
475
|
+
meta: {}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
// userRegister.uid = this.user.uid;
|
|
479
|
+
const result = await this.runFunction("currentUserRegister", userRegister as unknown as Record<string, unknown>);
|
|
480
|
+
const resultData = result.data as {success: boolean, message: string};
|
|
481
|
+
if (resultData.success) {
|
|
482
|
+
return this.sendResponse({
|
|
483
|
+
success: true,
|
|
484
|
+
message: "",
|
|
485
|
+
meta: {}
|
|
486
|
+
});
|
|
487
|
+
} else {
|
|
488
|
+
return this.sendResponse({
|
|
489
|
+
success: false,
|
|
490
|
+
message: resultData.message,
|
|
491
|
+
meta: {}
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
465
496
|
public registerUser = async (
|
|
466
497
|
userRegister: userRegister,
|
|
467
498
|
authProvider: authProviders = "email",
|
|
@@ -532,6 +563,7 @@ export const EdgeFirebase = class {
|
|
|
532
563
|
}
|
|
533
564
|
const initRoleHelper = {uid: response.user.uid}
|
|
534
565
|
initRoleHelper["edge-assignment-helper"] = {permissionType: "roles"}
|
|
566
|
+
this.user.loggingIn = true;
|
|
535
567
|
await setDoc(doc(this.db, "rule-helpers", response.user.uid), initRoleHelper);
|
|
536
568
|
await updateDoc(doc(this.db, "staged-users/" + userRegister.registrationCode), stagedUserUpdate)
|
|
537
569
|
this.logAnalyticsEvent("sign_up", { uid: response.user.uid});
|
|
@@ -959,6 +991,7 @@ export const EdgeFirebase = class {
|
|
|
959
991
|
this.user.oAuthCredential.idToken = "";
|
|
960
992
|
this.user.email = "";
|
|
961
993
|
this.user.loggedIn = false;
|
|
994
|
+
this.user.loggingIn = false;
|
|
962
995
|
this.user.meta = {};
|
|
963
996
|
this.user.roles = [];
|
|
964
997
|
this.user.specialPermissions = [];
|
|
@@ -984,6 +1017,7 @@ export const EdgeFirebase = class {
|
|
|
984
1017
|
this.user.oAuthCredential.idToken = "";
|
|
985
1018
|
this.user.loggedIn = false;
|
|
986
1019
|
this.user.logInError = true;
|
|
1020
|
+
this.user.loggingIn = false;
|
|
987
1021
|
this.user.logInErrorMessage = error.code + ": " + error.message;
|
|
988
1022
|
});
|
|
989
1023
|
};
|
|
@@ -1005,6 +1039,7 @@ export const EdgeFirebase = class {
|
|
|
1005
1039
|
public user: UserDataObject = reactive({
|
|
1006
1040
|
uid: null,
|
|
1007
1041
|
email: "",
|
|
1042
|
+
loggingIn: false,
|
|
1008
1043
|
loggedIn: false,
|
|
1009
1044
|
logInError: false,
|
|
1010
1045
|
logInErrorMessage: "",
|
|
@@ -1300,7 +1335,7 @@ export const EdgeFirebase = class {
|
|
|
1300
1335
|
}
|
|
1301
1336
|
};
|
|
1302
1337
|
|
|
1303
|
-
public startSnapshot = async(
|
|
1338
|
+
public startSnapshot = async (
|
|
1304
1339
|
collectionPath: string,
|
|
1305
1340
|
queryList: FirestoreQuery[] = [],
|
|
1306
1341
|
orderList: FirestoreOrderBy[] = [],
|
|
@@ -1312,20 +1347,32 @@ export const EdgeFirebase = class {
|
|
|
1312
1347
|
this.unsubscibe[collectionPath] = null;
|
|
1313
1348
|
if (canRead) {
|
|
1314
1349
|
const q = this.getQuery(collectionPath, queryList, orderList, max);
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1350
|
+
|
|
1351
|
+
return new Promise<actionResponse>((resolve, reject) => {
|
|
1352
|
+
const unsubscribe = onSnapshot(q, (querySnapshot) => {
|
|
1353
|
+
const items = {};
|
|
1354
|
+
querySnapshot.forEach((doc) => {
|
|
1355
|
+
const item = doc.data();
|
|
1356
|
+
item.docId = doc.id;
|
|
1357
|
+
items[doc.id] = item;
|
|
1358
|
+
});
|
|
1359
|
+
this.data[collectionPath] = items;
|
|
1360
|
+
this.unsubscibe[collectionPath] = unsubscribe;
|
|
1361
|
+
|
|
1362
|
+
// Resolve the Promise with the success response
|
|
1363
|
+
resolve(this.sendResponse({
|
|
1364
|
+
success: true,
|
|
1365
|
+
message: "",
|
|
1366
|
+
meta: {}
|
|
1367
|
+
}));
|
|
1368
|
+
}, (error) => {
|
|
1369
|
+
// Reject the Promise with the error response
|
|
1370
|
+
reject(this.sendResponse({
|
|
1371
|
+
success: false,
|
|
1372
|
+
message: `Error fetching data from "${collectionPath}": ${error.message}`,
|
|
1373
|
+
meta: {}
|
|
1374
|
+
}));
|
|
1321
1375
|
});
|
|
1322
|
-
this.data[collectionPath] = items;
|
|
1323
|
-
});
|
|
1324
|
-
this.unsubscibe[collectionPath] = unsubscribe;
|
|
1325
|
-
return this.sendResponse({
|
|
1326
|
-
success: true,
|
|
1327
|
-
message: "",
|
|
1328
|
-
meta: {}
|
|
1329
1376
|
});
|
|
1330
1377
|
} else {
|
|
1331
1378
|
return this.sendResponse({
|
package/package.json
CHANGED
package/src/functions.js
CHANGED
|
@@ -34,6 +34,56 @@ exports.removeNonRegisteredUser = functions.https.onCall(async (data, context) =
|
|
|
34
34
|
return { success: false, message: 'Non-registered user not found.' }
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
+
exports.currentUserRegister = functions.https.onCall(async (data, context) => {
|
|
38
|
+
if (data.uid === context.auth.uid) {
|
|
39
|
+
const stagedUser = await db.collection('staged-users').doc(data.registrationCode).get()
|
|
40
|
+
if (!stagedUser.exists) {
|
|
41
|
+
return { success: false, message: 'Registration code not found.' }
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const stagedUserData = await stagedUser.data()
|
|
45
|
+
let process = false
|
|
46
|
+
if (stagedUserData.isTemplate) {
|
|
47
|
+
process = true
|
|
48
|
+
}
|
|
49
|
+
if (!stagedUserData.isTemplate && stagedUserData.userId === '') {
|
|
50
|
+
process = true
|
|
51
|
+
}
|
|
52
|
+
if (!process) {
|
|
53
|
+
return { success: false, message: 'Registration code not valid.' }
|
|
54
|
+
}
|
|
55
|
+
const newRoles = stagedUserData.roles || {}
|
|
56
|
+
const currentUser = await db.collection('users').doc(data.uid).get()
|
|
57
|
+
const currentUserData = await currentUser.data()
|
|
58
|
+
const currentRoles = currentUserData.roles || {}
|
|
59
|
+
const currentUserCollectionPaths = currentUserData.collectionPaths || []
|
|
60
|
+
let newRole = {}
|
|
61
|
+
if (stagedUserData.subCreate && Object.keys(stagedUserData.subCreate).length !== 0 && stagedUserData.isTemplate) {
|
|
62
|
+
if (!data.dynamicDocumentFieldValue) {
|
|
63
|
+
return { success: false, message: 'Dynamic document field value is required.' }
|
|
64
|
+
}
|
|
65
|
+
const rootPath = stagedUserData.subCreate.rootPath
|
|
66
|
+
const newDoc = stagedUserData.subCreate.documentStructure
|
|
67
|
+
newDoc[stagedUserData.subCreate.dynamicDocumentField] = data.dynamicDocumentFieldValue
|
|
68
|
+
const addedDoc = await db.collection(rootPath).add(newDoc)
|
|
69
|
+
await db.collection(rootPath).doc(addedDoc.id).update({ docId: addedDoc.id })
|
|
70
|
+
newRole = { [`${rootPath}-${addedDoc.id}`]: { collectionPath: `${rootPath}-${addedDoc.id}`, role: stagedUserData.subCreate.role } }
|
|
71
|
+
}
|
|
72
|
+
const combinedRoles = { ...currentRoles, ...newRoles, ...newRole }
|
|
73
|
+
Object.values(combinedRoles).forEach((role) => {
|
|
74
|
+
if (!currentUserCollectionPaths.includes(role.collectionPath)) {
|
|
75
|
+
currentUserCollectionPaths.push(role.collectionPath)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
await db.collection('staged-users').doc(currentUserData.stagedDocId).update({ roles: combinedRoles, collectionPaths: currentUserCollectionPaths })
|
|
79
|
+
if (!stagedUserData.isTemplate) {
|
|
80
|
+
await db.collection('staged-users').doc(data.registrationCode).delete()
|
|
81
|
+
}
|
|
82
|
+
return { success: true, message: '' }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
37
87
|
exports.updateUser = functions.firestore.document('staged-users/{docId}').onUpdate((change, context) => {
|
|
38
88
|
const eventId = context.eventId
|
|
39
89
|
const eventRef = db.collection('events').doc(eventId)
|