@edgedev/firebase 1.7.3 → 1.7.5
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 +10 -9
- package/edgeFirebase.ts +104 -40
- package/images/default-collection-roles.png +0 -0
- package/images/root-collection-roles-old.png +0 -0
- package/images/root-collection-roles.png +0 -0
- package/images/root-user.png +0 -0
- package/package.json +1 -1
- /package/images/{root-user.jpg → root-user-old.jpg} +0 -0
package/README.md
CHANGED
|
@@ -374,12 +374,13 @@ Remove a role from a user for a collection:
|
|
|
374
374
|
|
|
375
375
|
### Root permissions and first user
|
|
376
376
|
|
|
377
|
-
You can assign a user access to all collections in the entire project by giving them a role on "-", which is used to define the root collection path. This would be for someone who is acting like a super admin. If this is your first user, you will need to manually set them up in the Firstore console. Once a root user is added manually you can use this user to add other "root users" or setup other collections and assign roles to them.
|
|
377
|
+
You can assign a user access to all collections in the entire project by giving them a role on "-", which is used to define the root collection path. This would be for someone who is acting like a super admin. If this is your first user, you will need to manually set them up in the Firstore console inside the "staged-users". Once a root user is added manually, you will need to "Register" that user using the docId of the "staged user" as the registration code, please see the user registration section of this documentation. You can use this user to add other "root users" or setup other collections and assign roles to them. You will also need to manually create the collection-data/-default- role permissions document (mentioned above) and the root permission document, see examples below:
|
|
378
378
|
|
|
379
|
-
|
|
380
|
-
| ------------------------------------------------------------ | ------------------------------------ |
|
|
379
|
+

|
|
381
380
|
|
|
381
|
+

|
|
382
382
|
|
|
383
|
+

|
|
383
384
|
|
|
384
385
|
### User special permissions
|
|
385
386
|
|
|
@@ -1005,38 +1006,38 @@ service cloud.firestore {
|
|
|
1005
1006
|
allow get: if checkPermission(seg1 + "-" + seg2, "read");
|
|
1006
1007
|
allow list: if checkPermission(seg1, "read");
|
|
1007
1008
|
allow create: if checkPermission(seg1, "write");
|
|
1008
|
-
allow update: if checkPermission(seg1, "write");
|
|
1009
|
+
allow update: if checkPermission(seg1 + "-" + seg2, "write");
|
|
1009
1010
|
allow delete: if checkPermission(seg1, "delete");
|
|
1010
1011
|
match /{seg3} {
|
|
1011
1012
|
allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
|
|
1012
1013
|
allow list: if checkPermission(seg1 + "-" + seg2, "read");
|
|
1013
1014
|
allow create: if checkPermission(seg1 + "-" + seg2, "write");
|
|
1014
|
-
allow update: if checkPermission(seg1 + "-" + seg2, "write");
|
|
1015
|
+
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
|
|
1015
1016
|
allow delete: if checkPermission(seg1 + "-" + seg2, "delete");
|
|
1016
1017
|
match /{seg4} {
|
|
1017
1018
|
allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
|
|
1018
1019
|
allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
|
|
1019
1020
|
allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
|
|
1020
|
-
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
|
|
1021
|
+
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
|
|
1021
1022
|
allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "delete");
|
|
1022
1023
|
|
|
1023
1024
|
match /{seg5} {
|
|
1024
1025
|
allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
|
|
1025
1026
|
allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
|
|
1026
1027
|
allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
|
|
1027
|
-
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
|
|
1028
|
+
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
|
|
1028
1029
|
allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "delete");
|
|
1029
1030
|
match /{seg6} {
|
|
1030
1031
|
allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
|
|
1031
1032
|
allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
|
|
1032
1033
|
allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
|
|
1033
|
-
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
|
|
1034
|
+
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
|
|
1034
1035
|
allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "delete");
|
|
1035
1036
|
match /{seg7} {
|
|
1036
1037
|
allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "read");
|
|
1037
1038
|
allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
|
|
1038
1039
|
allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
|
|
1039
|
-
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
|
|
1040
|
+
allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "write");
|
|
1040
1041
|
allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "delete");
|
|
1041
1042
|
}
|
|
1042
1043
|
}
|
package/edgeFirebase.ts
CHANGED
|
@@ -44,6 +44,9 @@ import {
|
|
|
44
44
|
connectAuthEmulator,
|
|
45
45
|
} from "firebase/auth";
|
|
46
46
|
|
|
47
|
+
|
|
48
|
+
import { getAnalytics, logEvent } from "firebase/analytics";
|
|
49
|
+
|
|
47
50
|
interface FirestoreQuery {
|
|
48
51
|
field: string;
|
|
49
52
|
operator: WhereFilterOp; // '==' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'array-contains-any';
|
|
@@ -108,7 +111,7 @@ interface newUser {
|
|
|
108
111
|
role: string,
|
|
109
112
|
dynamicDocumentField: string, // This is the field in the document that will be set by the value of "dynamicDocumentFieldValue" passed during registration, like "name"
|
|
110
113
|
documentStructure: {
|
|
111
|
-
[key: string]:
|
|
114
|
+
[key: string]: unknown
|
|
112
115
|
}
|
|
113
116
|
};
|
|
114
117
|
}
|
|
@@ -151,6 +154,7 @@ interface firebaseConfig {
|
|
|
151
154
|
messagingSenderId: string;
|
|
152
155
|
appId: string;
|
|
153
156
|
emulatorAuth?: string;
|
|
157
|
+
measurementId?: string;
|
|
154
158
|
emulatorFirestore?: string;
|
|
155
159
|
}
|
|
156
160
|
|
|
@@ -174,6 +178,7 @@ export const EdgeFirebase = class {
|
|
|
174
178
|
storageBucket: "",
|
|
175
179
|
messagingSenderId: "",
|
|
176
180
|
appId: "",
|
|
181
|
+
measurementId: "",
|
|
177
182
|
emulatorAuth: "",
|
|
178
183
|
emulatorFirestore: ""
|
|
179
184
|
},
|
|
@@ -196,6 +201,10 @@ export const EdgeFirebase = class {
|
|
|
196
201
|
connectFirestoreEmulator(this.db, "localhost", this.firebaseConfig.emulatorFirestore)
|
|
197
202
|
}
|
|
198
203
|
|
|
204
|
+
if (this.firebaseConfig.measurementId) {
|
|
205
|
+
this.anaytics = getAnalytics(this.app);
|
|
206
|
+
}
|
|
207
|
+
|
|
199
208
|
this.setOnAuthStateChanged();
|
|
200
209
|
}
|
|
201
210
|
|
|
@@ -205,6 +214,14 @@ export const EdgeFirebase = class {
|
|
|
205
214
|
public auth = null;
|
|
206
215
|
public db = null;
|
|
207
216
|
|
|
217
|
+
private anaytics = null;
|
|
218
|
+
|
|
219
|
+
public logAnalyticsEvent = (eventName: string, eventParams: object = {}) => {
|
|
220
|
+
if (this.anaytics) {
|
|
221
|
+
logEvent(this.anaytics, eventName, eventParams);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
208
225
|
private initUserMetaPermissions = async (docSnap): Promise<void> => {
|
|
209
226
|
this.user.meta = {};
|
|
210
227
|
if (docSnap.exists()) {
|
|
@@ -352,6 +369,7 @@ export const EdgeFirebase = class {
|
|
|
352
369
|
this.user.uid = userAuth.uid;
|
|
353
370
|
this.user.logInError = false;
|
|
354
371
|
this.user.logInErrorMessage = "";
|
|
372
|
+
this.logAnalyticsEvent("login", { uid: this.user.uid });
|
|
355
373
|
this.waitForUser();
|
|
356
374
|
} else {
|
|
357
375
|
this.user.email = "";
|
|
@@ -417,7 +435,7 @@ export const EdgeFirebase = class {
|
|
|
417
435
|
initRoleHelper["edge-assignment-helper"] = {permissionType: "roles"}
|
|
418
436
|
await setDoc(doc(this.db, "rule-helpers", response.user.uid), initRoleHelper);
|
|
419
437
|
await updateDoc(doc(this.db, "staged-users/" + userRegister.registrationCode), stagedUserUpdate)
|
|
420
|
-
|
|
438
|
+
this.logAnalyticsEvent("sign_up", { uid: response.user.uid});
|
|
421
439
|
return this.sendResponse({
|
|
422
440
|
success: true,
|
|
423
441
|
message: "",
|
|
@@ -806,6 +824,7 @@ export const EdgeFirebase = class {
|
|
|
806
824
|
if (this.unsubscibe[key] instanceof Function) {
|
|
807
825
|
this.unsubscibe[key]();
|
|
808
826
|
this.unsubscibe[key] = null;
|
|
827
|
+
this.data[key] = {};
|
|
809
828
|
}
|
|
810
829
|
}
|
|
811
830
|
signOut(this.auth).then(() => {
|
|
@@ -829,7 +848,7 @@ export const EdgeFirebase = class {
|
|
|
829
848
|
credentials.password
|
|
830
849
|
)
|
|
831
850
|
.then(() => {
|
|
832
|
-
|
|
851
|
+
// Do nothing
|
|
833
852
|
})
|
|
834
853
|
.catch((error) => {
|
|
835
854
|
this.user.email = "";
|
|
@@ -1480,62 +1499,107 @@ export const EdgeFirebase = class {
|
|
|
1480
1499
|
}
|
|
1481
1500
|
};
|
|
1482
1501
|
|
|
1483
|
-
//
|
|
1484
|
-
public
|
|
1502
|
+
// TODO: Add documentation for this function
|
|
1503
|
+
public changeDoc = async (
|
|
1485
1504
|
collectionPath: string,
|
|
1486
|
-
|
|
1505
|
+
docId: string,
|
|
1506
|
+
item: object
|
|
1487
1507
|
): Promise<actionResponse> => {
|
|
1488
|
-
const canWrite = await this.permissionCheck("write", collectionPath);
|
|
1508
|
+
const canWrite = await this.permissionCheck("write", collectionPath + "/" + docId);
|
|
1489
1509
|
if (!canWrite) {
|
|
1490
1510
|
return this.sendResponse({
|
|
1491
1511
|
success: false,
|
|
1492
|
-
message: `You do not have permission to write to "${collectionPath}"`,
|
|
1512
|
+
message: `You do not have permission to write to "${collectionPath}/${docId}"`,
|
|
1493
1513
|
meta: {}
|
|
1494
1514
|
});
|
|
1495
1515
|
} else {
|
|
1516
|
+
const docRef = doc(this.db, collectionPath, docId);
|
|
1517
|
+
const docSnap = await getDoc(docRef);
|
|
1518
|
+
if (!docSnap.exists()) {
|
|
1519
|
+
return this.sendResponse({
|
|
1520
|
+
success: false,
|
|
1521
|
+
message: `Document "${docId}" does not exist in "${collectionPath}"`,
|
|
1522
|
+
meta: {}
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1496
1525
|
const cloneItem = JSON.parse(JSON.stringify(item));
|
|
1497
1526
|
const currentTime = new Date().getTime();
|
|
1498
1527
|
cloneItem.last_updated = currentTime;
|
|
1499
1528
|
cloneItem.uid = this.user.uid;
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1529
|
+
await updateDoc(doc(this.db, collectionPath, docId), cloneItem);
|
|
1530
|
+
return this.sendResponse({
|
|
1531
|
+
success: true,
|
|
1532
|
+
message: "",
|
|
1533
|
+
meta: {}
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
public storeDoc = async (
|
|
1540
|
+
collectionPath: string,
|
|
1541
|
+
item: object,
|
|
1542
|
+
): Promise<actionResponse> => {
|
|
1543
|
+
|
|
1544
|
+
const cloneItem = JSON.parse(JSON.stringify(item));
|
|
1545
|
+
const currentTime = new Date().getTime();
|
|
1546
|
+
cloneItem.last_updated = currentTime;
|
|
1547
|
+
cloneItem.uid = this.user.uid;
|
|
1548
|
+
if (!Object.prototype.hasOwnProperty.call(cloneItem, "doc_created_at")) {
|
|
1549
|
+
cloneItem.doc_created_at = currentTime;
|
|
1550
|
+
}
|
|
1551
|
+
if (Object.prototype.hasOwnProperty.call(cloneItem, "docId")) {
|
|
1552
|
+
const canWrite = await this.permissionCheck("write", collectionPath + "/" + cloneItem.docId);
|
|
1553
|
+
if (!canWrite) {
|
|
1512
1554
|
return this.sendResponse({
|
|
1513
|
-
success:
|
|
1514
|
-
message: ""
|
|
1515
|
-
meta: {
|
|
1555
|
+
success: false,
|
|
1556
|
+
message: `You do not have permission to write to "${collectionPath}/${cloneItem.docId}"`,
|
|
1557
|
+
meta: {}
|
|
1516
1558
|
});
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
)
|
|
1522
|
-
|
|
1523
|
-
if (canRead) {
|
|
1524
|
-
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
1525
|
-
this.data[collectionPath][docRef.id] = cloneItem;
|
|
1526
|
-
}
|
|
1559
|
+
}
|
|
1560
|
+
const docId = cloneItem.docId;
|
|
1561
|
+
const canRead = this.permissionCheckOnly("read", collectionPath);
|
|
1562
|
+
if (canRead) {
|
|
1563
|
+
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
1564
|
+
this.data[collectionPath][docId] = cloneItem;
|
|
1527
1565
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1566
|
+
}
|
|
1567
|
+
await setDoc(doc(this.db, collectionPath, docId), cloneItem);
|
|
1568
|
+
return this.sendResponse({
|
|
1569
|
+
success: true,
|
|
1570
|
+
message: "",
|
|
1571
|
+
meta: {docId}
|
|
1572
|
+
});
|
|
1573
|
+
} else {
|
|
1574
|
+
const canWrite = await this.permissionCheck("write", collectionPath);
|
|
1575
|
+
if (!canWrite) {
|
|
1532
1576
|
return this.sendResponse({
|
|
1533
|
-
success:
|
|
1534
|
-
message: ""
|
|
1535
|
-
meta: {
|
|
1577
|
+
success: false,
|
|
1578
|
+
message: `You do not have permission to write to "${collectionPath}"`,
|
|
1579
|
+
meta: {}
|
|
1536
1580
|
});
|
|
1537
1581
|
}
|
|
1582
|
+
const docRef = await addDoc(
|
|
1583
|
+
collection(this.db, collectionPath),
|
|
1584
|
+
cloneItem
|
|
1585
|
+
);
|
|
1586
|
+
const canRead = this.permissionCheckOnly("read", collectionPath);
|
|
1587
|
+
if (canRead) {
|
|
1588
|
+
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
1589
|
+
this.data[collectionPath][docRef.id] = cloneItem;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
await this.storeDoc(
|
|
1593
|
+
collectionPath,
|
|
1594
|
+
{ ...cloneItem, docId: docRef.id }
|
|
1595
|
+
);
|
|
1596
|
+
return this.sendResponse({
|
|
1597
|
+
success: true,
|
|
1598
|
+
message: "",
|
|
1599
|
+
meta: {docId: docRef.id}
|
|
1600
|
+
});
|
|
1538
1601
|
}
|
|
1602
|
+
|
|
1539
1603
|
};
|
|
1540
1604
|
|
|
1541
1605
|
// Composable to delete a document
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
File without changes
|