@edgedev/firebase 1.5.12 → 1.6.0
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 +13 -12
- package/edgeFirebase.ts +183 -228
- package/package.json +1 -1
- package/pnpm-lock.yaml +2317 -0
package/edgeFirebase.ts
CHANGED
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
DocumentData,
|
|
22
22
|
setDoc,
|
|
23
23
|
updateDoc,
|
|
24
|
-
deleteField
|
|
24
|
+
deleteField,
|
|
25
|
+
arrayRemove,
|
|
26
|
+
arrayUnion,
|
|
25
27
|
} from "firebase/firestore";
|
|
26
28
|
|
|
27
29
|
import {
|
|
@@ -74,7 +76,7 @@ type action = "assign" | "read" | "write" | "delete";
|
|
|
74
76
|
|
|
75
77
|
interface role {
|
|
76
78
|
collectionPath: "-" | string; // - is root
|
|
77
|
-
role: "admin" | "user";
|
|
79
|
+
role: "admin" | "editor" | "writer" | "user";
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
interface specialPermission {
|
|
@@ -91,7 +93,6 @@ interface UserDataObject {
|
|
|
91
93
|
meta: object;
|
|
92
94
|
roles: role[];
|
|
93
95
|
specialPermissions: specialPermission[];
|
|
94
|
-
canAssignCollectionPaths: string[];
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
interface newUser {
|
|
@@ -215,7 +216,6 @@ export const EdgeFirebase = class {
|
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
218
|
this.user.specialPermissions = specialPermissions;
|
|
218
|
-
await this.listCollectionsCanAssign()
|
|
219
219
|
}
|
|
220
220
|
this.stopSnapshot('userMeta')
|
|
221
221
|
const metaUnsubscribe = onSnapshot(
|
|
@@ -253,14 +253,73 @@ export const EdgeFirebase = class {
|
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
this.user.specialPermissions = specialPermissions;
|
|
256
|
-
this.listCollectionsCanAssign()
|
|
257
256
|
}
|
|
258
257
|
}
|
|
259
258
|
);
|
|
260
259
|
this.unsubscibe.userMeta = metaUnsubscribe;
|
|
261
260
|
};
|
|
262
261
|
|
|
262
|
+
private startCollectionPermissionsSync = async (): Promise<void> => {
|
|
263
|
+
// TODO: In future get roles from user and only sync those collections
|
|
264
|
+
// Perhaps by getting all "first segments" and get all that start with that
|
|
265
|
+
const q = this.getQuery('collection-data');
|
|
266
|
+
const docs = await getDocs(q);
|
|
267
|
+
let items = {}
|
|
268
|
+
docs.forEach((doc) => {
|
|
269
|
+
const item = doc.data();
|
|
270
|
+
item.docId = doc.id;
|
|
271
|
+
items[doc.id] = item;
|
|
272
|
+
});
|
|
273
|
+
this.state.collectionPermissions = items;
|
|
274
|
+
if (!this.state.collectionPermissions['-default-']) {
|
|
275
|
+
const collectionItem = {
|
|
276
|
+
collectionPath: '-default-',
|
|
277
|
+
docId: '-default-',
|
|
278
|
+
admin: {
|
|
279
|
+
assign: true,
|
|
280
|
+
read: true,
|
|
281
|
+
write: true,
|
|
282
|
+
delete: true
|
|
283
|
+
},
|
|
284
|
+
editor: {
|
|
285
|
+
assign: false,
|
|
286
|
+
read: true,
|
|
287
|
+
write: true,
|
|
288
|
+
delete: true
|
|
289
|
+
},
|
|
290
|
+
writer: {
|
|
291
|
+
assign: false,
|
|
292
|
+
read: true,
|
|
293
|
+
write: true,
|
|
294
|
+
delete: false
|
|
295
|
+
},
|
|
296
|
+
user: {
|
|
297
|
+
assign: false,
|
|
298
|
+
read: true,
|
|
299
|
+
write: false,
|
|
300
|
+
delete: false
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
await setDoc(
|
|
304
|
+
doc(this.db, "collection-data", "-default-"),
|
|
305
|
+
collectionItem
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
this.stopSnapshot('collection-data');
|
|
309
|
+
const unsubscribe = onSnapshot(q, (querySnapshot) => {
|
|
310
|
+
items = {};
|
|
311
|
+
querySnapshot.forEach((doc) => {
|
|
312
|
+
const item = doc.data();
|
|
313
|
+
item.docId = doc.id;
|
|
314
|
+
items[doc.id] = item;
|
|
315
|
+
});
|
|
316
|
+
this.state.collectionPermissions = items;
|
|
317
|
+
});
|
|
318
|
+
this.unsubscibe['collection-data'] = unsubscribe
|
|
319
|
+
}
|
|
320
|
+
|
|
263
321
|
private startUserMetaSync = async (): Promise<void> => {
|
|
322
|
+
await this.startCollectionPermissionsSync()
|
|
264
323
|
await this.initUserMetaPermissions();
|
|
265
324
|
this.user.loggedIn = true;
|
|
266
325
|
};
|
|
@@ -408,19 +467,19 @@ export const EdgeFirebase = class {
|
|
|
408
467
|
const userSnap = await getDoc(userRef);
|
|
409
468
|
if (userSnap.data().roles) {
|
|
410
469
|
for (const collectionPath in userSnap.data().roles) {
|
|
411
|
-
const canAssign =
|
|
470
|
+
const canAssign = this.permissionCheck(
|
|
412
471
|
"assign",
|
|
413
472
|
collectionPath.replaceAll("-", "/")
|
|
414
473
|
);
|
|
415
474
|
if (canAssign) {
|
|
416
|
-
this.removeUserRoles(email, collectionPath.replaceAll("-", "/"));
|
|
475
|
+
await this.removeUserRoles(email, collectionPath.replaceAll("-", "/"));
|
|
417
476
|
removedFrom.push(collectionPath.replaceAll("-", "/"));
|
|
418
477
|
}
|
|
419
478
|
}
|
|
420
479
|
}
|
|
421
480
|
if (userSnap.data().specialPermissions) {
|
|
422
481
|
for (const collectionPath in userSnap.data().specialPermissions) {
|
|
423
|
-
const canAssign =
|
|
482
|
+
const canAssign = this.permissionCheck(
|
|
424
483
|
"assign",
|
|
425
484
|
collectionPath.replaceAll("-", "/")
|
|
426
485
|
);
|
|
@@ -449,11 +508,11 @@ export const EdgeFirebase = class {
|
|
|
449
508
|
};
|
|
450
509
|
|
|
451
510
|
public setUser = async (newUser: newUser): Promise<actionResponse> => {
|
|
452
|
-
const canAssignRole =
|
|
511
|
+
const canAssignRole = this.multiPermissionCheck(
|
|
453
512
|
"assign",
|
|
454
513
|
newUser.roles
|
|
455
514
|
);
|
|
456
|
-
const canAssignSpecialPermissions =
|
|
515
|
+
const canAssignSpecialPermissions = this.multiPermissionCheck(
|
|
457
516
|
"assign",
|
|
458
517
|
newUser.specialPermissions
|
|
459
518
|
);
|
|
@@ -469,7 +528,7 @@ export const EdgeFirebase = class {
|
|
|
469
528
|
specialPermissions: newUser.specialPermissions,
|
|
470
529
|
meta: newUser.meta
|
|
471
530
|
};
|
|
472
|
-
this.generateUserMeta(userMeta);
|
|
531
|
+
await this.generateUserMeta(userMeta);
|
|
473
532
|
return this.sendResponse({
|
|
474
533
|
success: true,
|
|
475
534
|
message: "",
|
|
@@ -495,17 +554,17 @@ export const EdgeFirebase = class {
|
|
|
495
554
|
}
|
|
496
555
|
};
|
|
497
556
|
|
|
498
|
-
private multiPermissionCheck =
|
|
557
|
+
private multiPermissionCheck = (
|
|
499
558
|
action: action,
|
|
500
559
|
collections = []
|
|
501
|
-
):
|
|
560
|
+
): permissionStatus => {
|
|
502
561
|
let canDo = true;
|
|
503
562
|
const badCollectionPaths = [];
|
|
504
563
|
// if (collections.length === 0) {
|
|
505
564
|
// canDo = false;
|
|
506
565
|
// }
|
|
507
566
|
for (const collection of collections) {
|
|
508
|
-
if (!(
|
|
567
|
+
if (!(this.permissionCheck(action, collection.collectionPath))) {
|
|
509
568
|
badCollectionPaths.push(collection.collectionPath);
|
|
510
569
|
canDo = false;
|
|
511
570
|
}
|
|
@@ -528,10 +587,10 @@ export const EdgeFirebase = class {
|
|
|
528
587
|
return response;
|
|
529
588
|
};
|
|
530
589
|
|
|
531
|
-
private permissionCheck =
|
|
590
|
+
private permissionCheck = (
|
|
532
591
|
action: action,
|
|
533
592
|
collectionPath: string
|
|
534
|
-
):
|
|
593
|
+
): boolean => {
|
|
535
594
|
const collection = collectionPath.split("/");
|
|
536
595
|
let index = collection.length;
|
|
537
596
|
let permissionData = {};
|
|
@@ -550,7 +609,7 @@ export const EdgeFirebase = class {
|
|
|
550
609
|
);
|
|
551
610
|
|
|
552
611
|
if (role) {
|
|
553
|
-
permissionData =
|
|
612
|
+
permissionData = this.getCollectionPermissions(
|
|
554
613
|
permissionCheck,
|
|
555
614
|
role.role
|
|
556
615
|
);
|
|
@@ -567,7 +626,7 @@ export const EdgeFirebase = class {
|
|
|
567
626
|
if (!permissionData[action]) {
|
|
568
627
|
const rootRole = this.user.roles.find((r) => r.collectionPath === "-");
|
|
569
628
|
if (rootRole) {
|
|
570
|
-
permissionData =
|
|
629
|
+
permissionData = this.getCollectionPermissions(
|
|
571
630
|
"-",
|
|
572
631
|
rootRole.role
|
|
573
632
|
);
|
|
@@ -582,33 +641,30 @@ export const EdgeFirebase = class {
|
|
|
582
641
|
return permissionData[action];
|
|
583
642
|
};
|
|
584
643
|
|
|
585
|
-
private getCollectionPermissions =
|
|
644
|
+
private getCollectionPermissions = (
|
|
586
645
|
collectionPath: string,
|
|
587
646
|
role: string
|
|
588
|
-
):
|
|
589
|
-
|
|
590
|
-
this.
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
assign: permissionData.assign
|
|
603
|
-
};
|
|
604
|
-
} else {
|
|
605
|
-
return {
|
|
606
|
-
read: false,
|
|
607
|
-
write: false,
|
|
608
|
-
delete: false,
|
|
609
|
-
assign: false
|
|
610
|
-
};
|
|
647
|
+
): permissions => {
|
|
648
|
+
if (Object.prototype.hasOwnProperty.call(this.state.collectionPermissions, collectionPath)) {
|
|
649
|
+
if (Object.prototype.hasOwnProperty.call(this.state.collectionPermissions[collectionPath], role)) {
|
|
650
|
+
const permissionData = this.state.collectionPermissions[collectionPath][role];
|
|
651
|
+
return {
|
|
652
|
+
read: permissionData.read,
|
|
653
|
+
write: permissionData.write,
|
|
654
|
+
delete: permissionData.delete,
|
|
655
|
+
assign: permissionData.assign
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (Object.prototype.hasOwnProperty.call(this.state.collectionPermissions, '-default-')) {
|
|
660
|
+
return this.state.collectionPermissions['-default-'][role];
|
|
611
661
|
}
|
|
662
|
+
return {
|
|
663
|
+
read: false,
|
|
664
|
+
write: false,
|
|
665
|
+
delete: false,
|
|
666
|
+
assign: false
|
|
667
|
+
};
|
|
612
668
|
};
|
|
613
669
|
|
|
614
670
|
private generateUserMeta = async (userMeta: userMeta): Promise<void> => {
|
|
@@ -620,17 +676,15 @@ export const EdgeFirebase = class {
|
|
|
620
676
|
const docRef = doc(this.db, "users", userMeta.docId);
|
|
621
677
|
const docSnap = await getDoc(docRef);
|
|
622
678
|
const docData = docSnap.data();
|
|
623
|
-
const canWrite =
|
|
679
|
+
const canWrite = this.permissionCheck("write", "users");
|
|
624
680
|
if (!docData || canWrite) {
|
|
625
|
-
setDoc(doc(this.db, "users", userMeta.docId), userMeta);
|
|
681
|
+
await setDoc(doc(this.db, "users", userMeta.docId), userMeta);
|
|
626
682
|
}
|
|
627
683
|
for (const role of roles) {
|
|
628
|
-
await this.
|
|
629
|
-
this.storeUserRoles(userMeta.docId, role.collectionPath, role.role);
|
|
684
|
+
await this.storeUserRoles(userMeta.docId, role.collectionPath, role.role);
|
|
630
685
|
}
|
|
631
686
|
for (const specialPermission of specialPermissions) {
|
|
632
|
-
await this.
|
|
633
|
-
this.storeUserSpecialPermissions(
|
|
687
|
+
await this.storeUserSpecialPermissions(
|
|
634
688
|
userMeta.docId,
|
|
635
689
|
specialPermission.collectionPath,
|
|
636
690
|
specialPermission.permissions
|
|
@@ -638,43 +692,6 @@ export const EdgeFirebase = class {
|
|
|
638
692
|
}
|
|
639
693
|
};
|
|
640
694
|
|
|
641
|
-
private generatePermissions = async (
|
|
642
|
-
collectionPath: string
|
|
643
|
-
): Promise<void> => {
|
|
644
|
-
const collection = collectionPath.split("/");
|
|
645
|
-
let index = collection.length;
|
|
646
|
-
while (index > 0) {
|
|
647
|
-
const collectionArray = JSON.parse(JSON.stringify(collection));
|
|
648
|
-
const permissionCheck = collectionArray.splice(0, index).join("/");
|
|
649
|
-
const hasPermissions = await this.collectionExists(permissionCheck);
|
|
650
|
-
const adminPermission: permissions = {
|
|
651
|
-
assign: true,
|
|
652
|
-
read: true,
|
|
653
|
-
write: true,
|
|
654
|
-
delete: true
|
|
655
|
-
};
|
|
656
|
-
const userPermission: permissions = {
|
|
657
|
-
assign: false,
|
|
658
|
-
read: false,
|
|
659
|
-
write: false,
|
|
660
|
-
delete: false
|
|
661
|
-
};
|
|
662
|
-
if (!hasPermissions) {
|
|
663
|
-
await this.storeCollectionPermissions(
|
|
664
|
-
permissionCheck,
|
|
665
|
-
"admin",
|
|
666
|
-
adminPermission
|
|
667
|
-
);
|
|
668
|
-
await this.storeCollectionPermissions(
|
|
669
|
-
permissionCheck,
|
|
670
|
-
"user",
|
|
671
|
-
userPermission
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
index = index - 1;
|
|
675
|
-
}
|
|
676
|
-
};
|
|
677
|
-
|
|
678
695
|
// Composable to logout
|
|
679
696
|
public logOut = (): void => {
|
|
680
697
|
signOut(this.auth)
|
|
@@ -790,7 +807,11 @@ export const EdgeFirebase = class {
|
|
|
790
807
|
meta: {},
|
|
791
808
|
roles: [],
|
|
792
809
|
specialPermissions: [],
|
|
793
|
-
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
public state = reactive({
|
|
813
|
+
collectionPermissions: {},
|
|
814
|
+
users: {},
|
|
794
815
|
});
|
|
795
816
|
|
|
796
817
|
public getDocData = async (
|
|
@@ -804,19 +825,10 @@ export const EdgeFirebase = class {
|
|
|
804
825
|
return docData;
|
|
805
826
|
};
|
|
806
827
|
|
|
807
|
-
private collectionExists =
|
|
828
|
+
private collectionExists = (
|
|
808
829
|
collectionPath: string
|
|
809
|
-
):
|
|
810
|
-
|
|
811
|
-
this.db,
|
|
812
|
-
"collection-data",
|
|
813
|
-
collectionPath.replaceAll("/", "-")
|
|
814
|
-
);
|
|
815
|
-
const collectionSnap = await getDoc(collectionRef);
|
|
816
|
-
if (collectionSnap.exists()) {
|
|
817
|
-
return true;
|
|
818
|
-
}
|
|
819
|
-
return false;
|
|
830
|
+
): boolean => {
|
|
831
|
+
return true;
|
|
820
832
|
};
|
|
821
833
|
|
|
822
834
|
private getStaticData = async (
|
|
@@ -831,12 +843,14 @@ export const EdgeFirebase = class {
|
|
|
831
843
|
const q = this.getQuery(collectionPath, queryList, orderList, max, last);
|
|
832
844
|
|
|
833
845
|
const docs = await getDocs(q);
|
|
846
|
+
|
|
834
847
|
const nextLast: DocumentData = docs.docs[docs.docs.length - 1];
|
|
835
848
|
docs.forEach((doc) => {
|
|
836
849
|
const item = doc.data();
|
|
837
850
|
item.docId = doc.id;
|
|
838
851
|
data[doc.id] = item;
|
|
839
852
|
});
|
|
853
|
+
|
|
840
854
|
return { data, next: nextLast };
|
|
841
855
|
};
|
|
842
856
|
|
|
@@ -946,7 +960,7 @@ export const EdgeFirebase = class {
|
|
|
946
960
|
orderList: FirestoreOrderBy[] = [],
|
|
947
961
|
max = 0
|
|
948
962
|
): Promise<actionResponse> => {
|
|
949
|
-
const canRead =
|
|
963
|
+
const canRead = permissionCheck("read", collectionPath);
|
|
950
964
|
|
|
951
965
|
if (canRead) {
|
|
952
966
|
this.collectionPath = collectionPath;
|
|
@@ -1032,13 +1046,13 @@ export const EdgeFirebase = class {
|
|
|
1032
1046
|
);
|
|
1033
1047
|
};
|
|
1034
1048
|
|
|
1035
|
-
public startSnapshot =
|
|
1049
|
+
public startSnapshot = (
|
|
1036
1050
|
collectionPath: string,
|
|
1037
1051
|
queryList: FirestoreQuery[] = [],
|
|
1038
1052
|
orderList: FirestoreOrderBy[] = [],
|
|
1039
1053
|
max = 0
|
|
1040
|
-
):
|
|
1041
|
-
const canRead =
|
|
1054
|
+
): actionResponse => {
|
|
1055
|
+
const canRead = this.permissionCheck("read", collectionPath);
|
|
1042
1056
|
this.data[collectionPath] = {};
|
|
1043
1057
|
this.stopSnapshot(collectionPath);
|
|
1044
1058
|
this.unsubscibe[collectionPath] = null;
|
|
@@ -1068,114 +1082,49 @@ export const EdgeFirebase = class {
|
|
|
1068
1082
|
}
|
|
1069
1083
|
};
|
|
1070
1084
|
|
|
1071
|
-
private listCollectionsCanAssign = async (): Promise<void> => {
|
|
1072
|
-
let collectionPaths = [];
|
|
1073
|
-
for (const role of this.user.roles) {
|
|
1074
|
-
const canAssign = await this.permissionCheck(
|
|
1075
|
-
"assign",
|
|
1076
|
-
role.collectionPath
|
|
1077
|
-
);
|
|
1078
|
-
if (canAssign) {
|
|
1079
|
-
collectionPaths.push(role.collectionPath);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
for (const specialPermission of this.user.specialPermissions) {
|
|
1083
|
-
const canAssign = await this.permissionCheck(
|
|
1084
|
-
"assign",
|
|
1085
|
-
specialPermission.collectionPath
|
|
1086
|
-
);
|
|
1087
|
-
if (canAssign) {
|
|
1088
|
-
collectionPaths.push(specialPermission.collectionPath);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
collectionPaths = [...new Set(collectionPaths)];
|
|
1092
|
-
let collectionPathList = [];
|
|
1093
|
-
for (const collectionPath of collectionPaths) {
|
|
1094
|
-
if (collectionPath === "-") {
|
|
1095
|
-
const collections = await getDocs(
|
|
1096
|
-
collection(this.db, "collection-data")
|
|
1097
|
-
);
|
|
1098
|
-
collections.forEach((doc) => {
|
|
1099
|
-
collectionPathList.push(doc.id);
|
|
1100
|
-
});
|
|
1101
|
-
} else {
|
|
1102
|
-
const collections = await getDocs(
|
|
1103
|
-
query(
|
|
1104
|
-
collection(this.db, "collection-data"),
|
|
1105
|
-
where("collectionPath", ">=", collectionPath),
|
|
1106
|
-
where("collectionPath", "<", collectionPath + "\uF8FF")
|
|
1107
|
-
)
|
|
1108
|
-
);
|
|
1109
|
-
collections.forEach((doc) => {
|
|
1110
|
-
collectionPathList.push(doc.id);
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
collectionPathList = [...new Set(collectionPathList)];
|
|
1115
|
-
this.user.canAssignCollectionPaths = collectionPathList;
|
|
1116
|
-
};
|
|
1117
|
-
|
|
1118
|
-
public stopUsersSnapshot = (): void => {
|
|
1119
|
-
const keys = Object.keys(this.usersByCollections).filter((key) => key.startsWith('ROLES|') || key.startsWith('SPECIALPERMISSIONS|'));
|
|
1120
|
-
keys.forEach((key) => {
|
|
1121
|
-
this.stopSnapshot(key);
|
|
1122
|
-
delete this.usersByCollections[key];
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
1085
|
public startUsersSnapshot = (collectionPath = ''): void => {
|
|
1127
|
-
this.
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1086
|
+
this.stopSnapshot('users')
|
|
1087
|
+
// TODO: need to build users object appropriately and only show roles
|
|
1088
|
+
// and special permmisions for collectionPaths the user has assign access for
|
|
1089
|
+
this.state.users = {};
|
|
1090
|
+
if (collectionPath) {
|
|
1091
|
+
if (this.permissionCheck('assign', collectionPath)) {
|
|
1092
|
+
const q = query(
|
|
1133
1093
|
collection(this.db, "users"),
|
|
1134
1094
|
where(
|
|
1135
|
-
"
|
|
1136
|
-
"
|
|
1137
|
-
|
|
1095
|
+
"collectionPaths",
|
|
1096
|
+
"array-contains",
|
|
1097
|
+
collectionPath.replaceAll('/', '-')
|
|
1138
1098
|
)
|
|
1139
1099
|
)
|
|
1140
|
-
const
|
|
1100
|
+
const unsubscibe = onSnapshot(q, (querySnapshot) => {
|
|
1141
1101
|
const items = {};
|
|
1142
1102
|
querySnapshot.forEach((doc) => {
|
|
1143
1103
|
const user = doc.data();
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1104
|
+
const newRoles = [];
|
|
1105
|
+
const newSpecialPermissions = [];
|
|
1106
|
+
|
|
1107
|
+
if (user.roles) {
|
|
1108
|
+
const roles: role[] = Object.values(user.roles);
|
|
1109
|
+
roles.forEach((role) => {
|
|
1110
|
+
if (this.permissionCheck('assign', role.collectionPath)) {
|
|
1111
|
+
newRoles.push(role)
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
if (user.specialPermissions) {
|
|
1116
|
+
const permissions: specialPermission[] = Object.values(user.specialPermissions);
|
|
1117
|
+
permissions.forEach(permission => {
|
|
1118
|
+
if (this.permissionCheck('assign', permission.collectionPath)) {
|
|
1119
|
+
newSpecialPermissions.push(permission)
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1153
1122
|
}
|
|
1154
|
-
items[doc.id] = item;
|
|
1155
|
-
});
|
|
1156
|
-
this.usersByCollections['ROLES|' + collectionPathCheck] = items;
|
|
1157
|
-
});
|
|
1158
|
-
this.unsubscibe['ROLES|' + collectionPathCheck] = rolesUnsubscribe
|
|
1159
|
-
|
|
1160
|
-
this.usersByCollections['SPECIALPERMISSIONS|' + collectionPathCheck] = {};
|
|
1161
|
-
q = query(
|
|
1162
|
-
collection(this.db, "users"),
|
|
1163
|
-
where(
|
|
1164
|
-
"specialPermissions." + collectionPathCheck + ".collectionPath",
|
|
1165
|
-
"==",
|
|
1166
|
-
collectionPathCheck
|
|
1167
|
-
)
|
|
1168
|
-
)
|
|
1169
|
-
|
|
1170
|
-
const specialPermissionsunsubscribe = onSnapshot(q, (querySnapshot) => {
|
|
1171
|
-
const items = {};
|
|
1172
|
-
querySnapshot.forEach((doc) => {
|
|
1173
|
-
const user = doc.data();
|
|
1174
1123
|
const item = {
|
|
1175
1124
|
docId: user.docId,
|
|
1176
1125
|
email: user.email,
|
|
1177
|
-
roles:
|
|
1178
|
-
specialPermissions:
|
|
1126
|
+
roles: newRoles,
|
|
1127
|
+
specialPermissions: newSpecialPermissions,
|
|
1179
1128
|
meta: user.meta,
|
|
1180
1129
|
last_updated: user.last_updated,
|
|
1181
1130
|
userId: user.userId,
|
|
@@ -1183,9 +1132,9 @@ export const EdgeFirebase = class {
|
|
|
1183
1132
|
}
|
|
1184
1133
|
items[doc.id] = item;
|
|
1185
1134
|
});
|
|
1186
|
-
this.
|
|
1135
|
+
this.state.users = items;
|
|
1187
1136
|
});
|
|
1188
|
-
this.unsubscibe
|
|
1137
|
+
this.unsubscibe.users = unsubscibe;
|
|
1189
1138
|
}
|
|
1190
1139
|
}
|
|
1191
1140
|
};
|
|
@@ -1194,11 +1143,14 @@ export const EdgeFirebase = class {
|
|
|
1194
1143
|
email: string,
|
|
1195
1144
|
collectionPath: string
|
|
1196
1145
|
): Promise<actionResponse> => {
|
|
1197
|
-
const canAssign =
|
|
1146
|
+
const canAssign = this.permissionCheck("assign", collectionPath);
|
|
1198
1147
|
if (canAssign) {
|
|
1199
1148
|
await updateDoc(doc(this.db, "users/" + email), {
|
|
1200
1149
|
["roles." + collectionPath.replaceAll("/", "-")]: deleteField()
|
|
1201
1150
|
});
|
|
1151
|
+
await updateDoc(doc(this.db, "users/" + email), {
|
|
1152
|
+
collectionPaths: arrayRemove(collectionPath.replaceAll("/", "-"))
|
|
1153
|
+
});
|
|
1202
1154
|
return this.sendResponse({
|
|
1203
1155
|
success: true,
|
|
1204
1156
|
message: "",
|
|
@@ -1218,12 +1170,15 @@ export const EdgeFirebase = class {
|
|
|
1218
1170
|
email: string,
|
|
1219
1171
|
collectionPath: string
|
|
1220
1172
|
): Promise<actionResponse> => {
|
|
1221
|
-
const canAssign =
|
|
1173
|
+
const canAssign = this.permissionCheck("assign", collectionPath);
|
|
1222
1174
|
if (canAssign) {
|
|
1223
1175
|
await updateDoc(doc(this.db, "users/" + email), {
|
|
1224
1176
|
["specialPermissions." + collectionPath.replaceAll("/", "-")]:
|
|
1225
1177
|
deleteField()
|
|
1226
1178
|
});
|
|
1179
|
+
await updateDoc(doc(this.db, "users/" + email), {
|
|
1180
|
+
collectionPaths: arrayRemove(collectionPath.replaceAll("/", "-"))
|
|
1181
|
+
});
|
|
1227
1182
|
return this.sendResponse({
|
|
1228
1183
|
success: true,
|
|
1229
1184
|
message: "",
|
|
@@ -1244,7 +1199,7 @@ export const EdgeFirebase = class {
|
|
|
1244
1199
|
collectionPath: string,
|
|
1245
1200
|
permissions: permissions
|
|
1246
1201
|
): Promise<actionResponse> => {
|
|
1247
|
-
const canAssign =
|
|
1202
|
+
const canAssign = this.permissionCheck("assign", collectionPath);
|
|
1248
1203
|
if (canAssign) {
|
|
1249
1204
|
const collectionExists = await this.collectionExists(collectionPath);
|
|
1250
1205
|
if (collectionExists) {
|
|
@@ -1254,7 +1209,10 @@ export const EdgeFirebase = class {
|
|
|
1254
1209
|
permissions
|
|
1255
1210
|
}
|
|
1256
1211
|
};
|
|
1257
|
-
updateDoc(doc(this.db, "users/" + email), permissionItem);
|
|
1212
|
+
await updateDoc(doc(this.db, "users/" + email), permissionItem);
|
|
1213
|
+
await updateDoc(doc(this.db, "users/" + email), {
|
|
1214
|
+
collectionPaths: arrayUnion(collectionPath.replaceAll("/", "-"))
|
|
1215
|
+
});
|
|
1258
1216
|
return this.sendResponse({
|
|
1259
1217
|
success: true,
|
|
1260
1218
|
message: "",
|
|
@@ -1280,12 +1238,12 @@ export const EdgeFirebase = class {
|
|
|
1280
1238
|
private storeUserRoles = async (
|
|
1281
1239
|
email: string,
|
|
1282
1240
|
collectionPath: string,
|
|
1283
|
-
role: "admin" | "user"
|
|
1241
|
+
role: "admin" | "editor" | "writer" | "user"
|
|
1284
1242
|
): Promise<actionResponse> => {
|
|
1285
|
-
const canAssign =
|
|
1243
|
+
const canAssign = this.permissionCheck("assign", collectionPath);
|
|
1286
1244
|
|
|
1287
1245
|
if (canAssign) {
|
|
1288
|
-
if (role === "admin" || role === "user") {
|
|
1246
|
+
if (role === "admin" || role === "user" || role === "editor" || role === "writer") {
|
|
1289
1247
|
const collectionExists = await this.collectionExists(collectionPath);
|
|
1290
1248
|
if (collectionExists) {
|
|
1291
1249
|
const roleItem = {
|
|
@@ -1295,7 +1253,10 @@ export const EdgeFirebase = class {
|
|
|
1295
1253
|
}
|
|
1296
1254
|
};
|
|
1297
1255
|
|
|
1298
|
-
updateDoc(doc(this.db, "users/" + email), roleItem);
|
|
1256
|
+
await updateDoc(doc(this.db, "users/" + email), roleItem);
|
|
1257
|
+
await updateDoc(doc(this.db, "users/" + email), {
|
|
1258
|
+
collectionPaths: arrayUnion(collectionPath.replaceAll("/", "-"))
|
|
1259
|
+
});
|
|
1299
1260
|
return this.sendResponse({
|
|
1300
1261
|
success: true,
|
|
1301
1262
|
message: "",
|
|
@@ -1311,7 +1272,7 @@ export const EdgeFirebase = class {
|
|
|
1311
1272
|
} else {
|
|
1312
1273
|
return this.sendResponse({
|
|
1313
1274
|
success: false,
|
|
1314
|
-
message: "Role must be either 'admin' or 'user'",
|
|
1275
|
+
message: "Role must be either 'admin' or 'editor' or 'writer' or 'user'",
|
|
1315
1276
|
meta: {}
|
|
1316
1277
|
});
|
|
1317
1278
|
}
|
|
@@ -1328,7 +1289,7 @@ export const EdgeFirebase = class {
|
|
|
1328
1289
|
public removeCollectionPermissions = async (
|
|
1329
1290
|
collectionPath: string,
|
|
1330
1291
|
): Promise<actionResponse> => {
|
|
1331
|
-
const canAssign =
|
|
1292
|
+
const canAssign = this.permissionCheck("assign", collectionPath);
|
|
1332
1293
|
if (canAssign) {
|
|
1333
1294
|
await deleteDoc(doc(this.db, "collection-data", collectionPath.replaceAll("/", "-")));
|
|
1334
1295
|
return this.sendResponse({
|
|
@@ -1347,13 +1308,13 @@ export const EdgeFirebase = class {
|
|
|
1347
1308
|
|
|
1348
1309
|
public storeCollectionPermissions = async (
|
|
1349
1310
|
collectionPath: string,
|
|
1350
|
-
role: "admin" | "user",
|
|
1311
|
+
role: "admin" | "editor" | "writer" | "user",
|
|
1351
1312
|
permissions: permissions
|
|
1352
1313
|
): Promise<actionResponse> => {
|
|
1353
|
-
const canAssign =
|
|
1314
|
+
const canAssign = this.permissionCheck("assign", collectionPath);
|
|
1354
1315
|
// TODO: check if collectionPath starts with "users" and deny if so
|
|
1355
1316
|
if (canAssign) {
|
|
1356
|
-
if (role === "admin" || role === "user") {
|
|
1317
|
+
if (role === "admin" || role === "editor" || role === "writer" || role === "user") {
|
|
1357
1318
|
const currentTime = new Date().getTime();
|
|
1358
1319
|
|
|
1359
1320
|
const collectionItem = {
|
|
@@ -1385,7 +1346,7 @@ export const EdgeFirebase = class {
|
|
|
1385
1346
|
} else {
|
|
1386
1347
|
return this.sendResponse({
|
|
1387
1348
|
success: false,
|
|
1388
|
-
message: "Role must be either 'admin' or 'user'",
|
|
1349
|
+
message: "Role must be either 'admin' or 'editor' or 'writer' or 'user'",
|
|
1389
1350
|
meta: {}
|
|
1390
1351
|
});
|
|
1391
1352
|
}
|
|
@@ -1403,9 +1364,8 @@ export const EdgeFirebase = class {
|
|
|
1403
1364
|
public storeDoc = async (
|
|
1404
1365
|
collectionPath: string,
|
|
1405
1366
|
item: object,
|
|
1406
|
-
generatePermissions = true
|
|
1407
1367
|
): Promise<actionResponse> => {
|
|
1408
|
-
const canWrite =
|
|
1368
|
+
const canWrite = this.permissionCheck("write", collectionPath);
|
|
1409
1369
|
if (!canWrite) {
|
|
1410
1370
|
return this.sendResponse({
|
|
1411
1371
|
success: false,
|
|
@@ -1413,10 +1373,6 @@ export const EdgeFirebase = class {
|
|
|
1413
1373
|
meta: {}
|
|
1414
1374
|
});
|
|
1415
1375
|
} else {
|
|
1416
|
-
if (generatePermissions) {
|
|
1417
|
-
collectionPath = collectionPath.replaceAll("-", "_");
|
|
1418
|
-
this.generatePermissions(collectionPath);
|
|
1419
|
-
}
|
|
1420
1376
|
const cloneItem = JSON.parse(JSON.stringify(item));
|
|
1421
1377
|
const currentTime = new Date().getTime();
|
|
1422
1378
|
cloneItem.last_updated = currentTime;
|
|
@@ -1426,13 +1382,13 @@ export const EdgeFirebase = class {
|
|
|
1426
1382
|
}
|
|
1427
1383
|
if (Object.prototype.hasOwnProperty.call(cloneItem, "docId")) {
|
|
1428
1384
|
const docId = cloneItem.docId;
|
|
1429
|
-
const canRead =
|
|
1385
|
+
const canRead = this.permissionCheck("read", collectionPath);
|
|
1430
1386
|
if (canRead) {
|
|
1431
1387
|
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
1432
1388
|
this.data[collectionPath][docId] = cloneItem;
|
|
1433
1389
|
}
|
|
1434
1390
|
}
|
|
1435
|
-
setDoc(doc(this.db, collectionPath, docId), cloneItem);
|
|
1391
|
+
await setDoc(doc(this.db, collectionPath, docId), cloneItem);
|
|
1436
1392
|
return this.sendResponse({
|
|
1437
1393
|
success: true,
|
|
1438
1394
|
message: "",
|
|
@@ -1443,16 +1399,15 @@ export const EdgeFirebase = class {
|
|
|
1443
1399
|
collection(this.db, collectionPath),
|
|
1444
1400
|
cloneItem
|
|
1445
1401
|
);
|
|
1446
|
-
const canRead =
|
|
1402
|
+
const canRead = this.permissionCheck("read", collectionPath);
|
|
1447
1403
|
if (canRead) {
|
|
1448
1404
|
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
1449
1405
|
this.data[collectionPath][docRef.id] = cloneItem;
|
|
1450
1406
|
}
|
|
1451
1407
|
}
|
|
1452
|
-
this.storeDoc(
|
|
1408
|
+
await this.storeDoc(
|
|
1453
1409
|
collectionPath,
|
|
1454
|
-
{ ...cloneItem, docId: docRef.id }
|
|
1455
|
-
generatePermissions
|
|
1410
|
+
{ ...cloneItem, docId: docRef.id }
|
|
1456
1411
|
);
|
|
1457
1412
|
return this.sendResponse({
|
|
1458
1413
|
success: true,
|
|
@@ -1468,7 +1423,7 @@ export const EdgeFirebase = class {
|
|
|
1468
1423
|
collectionPath: string,
|
|
1469
1424
|
docId: string
|
|
1470
1425
|
): Promise<actionResponse> => {
|
|
1471
|
-
const canDelete =
|
|
1426
|
+
const canDelete = this.permissionCheck("delete", collectionPath);
|
|
1472
1427
|
if (canDelete) {
|
|
1473
1428
|
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
1474
1429
|
if (
|
|
@@ -1477,7 +1432,7 @@ export const EdgeFirebase = class {
|
|
|
1477
1432
|
delete this.data[collectionPath][docId];
|
|
1478
1433
|
}
|
|
1479
1434
|
}
|
|
1480
|
-
deleteDoc(doc(this.db, collectionPath, docId));
|
|
1435
|
+
await deleteDoc(doc(this.db, collectionPath, docId));
|
|
1481
1436
|
return this.sendResponse({
|
|
1482
1437
|
success: true,
|
|
1483
1438
|
message: "",
|