@edgedev/firebase 1.7.8 → 1.7.9

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 CHANGED
@@ -12,6 +12,10 @@ A Vue 3 / Nuxt 3 Plugin or Nuxt 3 global composable for firebase authentication
12
12
  **[Await and response](#responses)**
13
13
  **[Firestore Rules](#firestore-rules)**
14
14
 
15
+
16
+
17
+ Before diving into the documentation, it's important to note that when using this package, you should always use `await` or wait for promises to resolve. This ensures that the Rule Helpers work correctly and provides the necessary information for verifying user access rights. Failing to wait for promises may lead to inconsistencies in access control and unexpected behavior in your application. For more information about how this class handles user permissions, please refer to the section below: **Rule Helpers: Managing User Permissions in Firestore**.
18
+
15
19
  # Installation
16
20
 
17
21
  pnpm install @edgedev/firebase
@@ -105,7 +109,13 @@ const edgeFirebase = inject("edgeFirebase");
105
109
  </script>
106
110
  ```
107
111
 
108
- ### Firebase Trigger function.
112
+ ### Firebase Trigger functions.
113
+
114
+ These function react to updates in the `staged-users` Firestore collection. This trigger is designed to help maintain data consistency between the `staged-users` and `users` collections. When a document in the `staged-users` collection is updated, the trigger performs checks and updates the corresponding user data in the `users` collection, ensuring that both collections stay in sync.
115
+
116
+ The trigger considers various scenarios such as the presence of a `userId` field, differences between the old and new `templateUserId` fields, and event processing status. It uses helper functions like `setUser`, `shouldProcess`, and `markProcessed` to manage these scenarios and make the necessary updates to the `users` collection. These functions handle tasks like updating or creating user documents, checking if an event should be processed, and marking an event as processed.
117
+
118
+ In essence, the `updateUser` trigger streamlines user data management by automatically synchronizing updates between the `staged-users` and `users` collections in your Firebase project and adds another layer of security.
109
119
 
110
120
  User mangement requires setting up in this firestore trigger function and helper functions in your firebase functions:
111
121
 
@@ -253,7 +263,7 @@ edgeFirebase.addUser({
253
263
  subCreate: {
254
264
  rootPath: 'myItems',
255
265
  role: 'admin',
256
- dynamicDocumentField: 'name',
266
+ dynamicDocumentFieldValue: 'name',
257
267
  documentStructure: {
258
268
  name: '',
259
269
  },
@@ -299,14 +309,33 @@ After someoene has been added as a user they will need to "self register" to beg
299
309
 
300
310
  ```typescript
301
311
  interface userRegister {
302
- email: string;
303
- password: string;
312
+ email?: string;
313
+ password?: string;
304
314
  meta: object;
305
315
  registrationCode: string;
306
316
  dynamicDocumentFieldValue?: string;
307
317
  }
308
318
  ```
309
319
 
320
+ #### Registration using Microsoft Provider.
321
+
322
+ Calling this will generate a Microsoft Sign In Popup and register the user using the Microsoft credentials.
323
+
324
+ ```javascript
325
+ edgeFirebase.registerUser(
326
+ {
327
+ meta: {
328
+ firstName: "John",
329
+ lastName: "Doe"
330
+ } // This is just an example of meta, it can contain any fields and any number of fields.
331
+ registrationCode: (document id) // This is the document id of either an added user or a template user, when using a template you can simply hardcode the registrationCode of the remplate to allow self registration.
332
+ dynamicDocumentFieldValue: "" // Optional - See explaintion above about self registration and dynamic collectionPath for user roles.
333
+ },
334
+ 'microsoft', // This is the authProvider only 'email' or 'microsoft' are supported, default is 'email',
335
+ ["mail.read", "calendars.read"] // This is a list of scopes to pass to Microsoft, the field is optional.
336
+ );
337
+ ```
338
+
310
339
 
311
340
 
312
341
  ### Explanation of permissions
@@ -408,7 +437,13 @@ Remove user special permissions:
408
437
  );
409
438
  ```
410
439
 
440
+ ### Rule Helpers: Managing User Permissions in Firestore
411
441
 
442
+ The package provides a utility designed to assist in managing user permissions for various actions in your Firestore project. By taking a `collectionPath` and an `action` as input parameters, it determines the user's role and special permissions and saves a `RuleCheck` object to the `rule-helpers` collection.
443
+
444
+ The `RuleCheck` object contains the permission type, permission check path, full path, and action, providing the necessary information to verify the user's access rights. By iterating through the user's roles and special permissions, the class identifies the correct permission check path and type.
445
+
446
+ The class plays a crucial role in maintaining data security and access control within your Firestore project. It ensures that users can only perform actions they are authorized to, based on their roles and special permissions.
412
447
 
413
448
  ### Remove user
414
449
 
@@ -420,6 +455,26 @@ edgeFirebase.removeUser(docId);
420
455
 
421
456
 
422
457
 
458
+ ### Delete Self
459
+
460
+ This function allows a user to delete their own account. It removes the user's document from both the `users` and `staged-users` collections in the database and also deletes the user's authentication record. The function returns an `actionResponse` object indicating the success or failure of the operation.
461
+
462
+ #### Usage
463
+
464
+ To delete the current user's account, call the `deleteSelf` function:
465
+
466
+ ```javascript
467
+ const response = await edgeFirebase.deleteSelf();
468
+
469
+ if (response.success) {
470
+ console.log("Account deleted successfully.");
471
+ } else {
472
+ console.log("Failed to delete account:", response.message);
473
+ }
474
+ ```
475
+
476
+
477
+
423
478
  ### Users Snapshot Data
424
479
 
425
480
  This will create a reactive object (state.users) that contains the members of the collection passed to the snapshot if the user running the function has assign access for, it will be a listed index by docId.
@@ -478,7 +533,7 @@ interface permissions {
478
533
 
479
534
  # Firebase Authentication
480
535
 
481
- (currently only sign in with email and password is supported)
536
+ ### Email and Password Login:
482
537
 
483
538
  ```javascript
484
539
  edgeFirebase.logIn(
@@ -489,7 +544,33 @@ interface permissions {
489
544
  );
490
545
  ```
491
546
 
492
- #### User information is contained in: edgeFirebase.user
547
+ ### Log In with Microsoft
548
+
549
+ This function allows users to log in using their Microsoft account. You can also specify an array of provider scopes if you want to request additional permissions from the user. The function returns a Promise that resolves when the sign-in process is complete. If the user does not exist, it will trigger an error and log the user out.
550
+
551
+ #### Usage
552
+
553
+ To log in with a Microsoft account, call the `logInWithMicrosoft` function. You can also pass an array of provider scopes as an optional parameter.
554
+
555
+ ```javascript
556
+ // Log in using Microsoft account without additional provider scopes
557
+ edgeFirebase.logInWithMicrosoft();
558
+
559
+ // Log in using Microsoft account with additional provider scopes
560
+ const providerScopes = ["User.Read", "Calendars.Read"];
561
+ edgeFirebase.logInWithMicrosoft(providerScopes);
562
+ ```
563
+
564
+ #### Parameters
565
+
566
+ - `providerScopes` (optional): An array of strings representing the additional provider scopes to request from the user. Defaults to an empty array.
567
+
568
+ #### Returns
569
+
570
+ A Promise that resolves when the sign-in process is complete. The Promise resolves to void, but any errors that occur during the sign-in process are captured and stored in the `this.user.logInError` and `this.user.logInErrorMessage` properties.
571
+
572
+ #### After Login, User information is contained in: edgeFirebase.user
573
+
493
574
  The user object is reactive and contains these items:
494
575
  ```typescript
495
576
  interface UserDataObject {
@@ -607,6 +688,20 @@ edgeFirebase.storeDoc("myItems", addItem);
607
688
  ```
608
689
  Note: When a document is written to the collection several other keys are added that can be referenced: **doc_created_at**(timestamp of doc creation), **last_updated**(timestamp document last written), **uid**(the user id of the user that updated or created the document).
609
690
 
691
+ ### Updating a Document Field(s)
692
+
693
+ In contrast to the `storeDoc` method which adds or updates an entire document, you can use `edgeFirebase.changeDoc(collectionPath, docId, object)` to update individual fields in a document. This method allows you to specify the collection path, document ID, and the fields to update in the form of an object. It will only update the fields provided in the object while keeping the existing data in the document intact.
694
+
695
+ ```javascript
696
+ <script setup>
697
+ const docId = "exampleDocumentId";
698
+ const updateItem = { title: "Updated Cool Thing" };
699
+ edgeFirebase.changeDoc("myItems", docId, updateItem);
700
+ </script>
701
+ ```
702
+
703
+ In this example, the `changeDoc` method will update the title field of the specified document with the new value while preserving other fields. This is particularly useful when you need to modify a single field or a subset of fields in a document without affecting the rest of the data.
704
+
610
705
  ### Getting a single Document.
611
706
  If you want to query a single document from a collection use: **edgeFirebase.getDocData(collectionPath, docId)**
612
707
  ```javascript
@@ -626,7 +721,7 @@ const singleDoc = edgeFirebase.removeDoc("myItems", docId);
626
721
  ```
627
722
 
628
723
  # Firestore Snapshot Listeners
629
- ### Starting a snapshot listener on a collection.
724
+ ### Starting a Snapshot listener on a collection
630
725
  To start a snapshot listen on a collection use: **edgeFirebase.startSnapshot(collectionPath)**
631
726
  ```javascript
632
727
  <script setup>
@@ -643,7 +738,22 @@ Once you have started a snapshot reactive data for that snapshot will be availab
643
738
  </div>
644
739
  </template>
645
740
  ```
741
+ ### Starting a Snapshot Listener on a Document
742
+
743
+ To start a snapshot listener on a specific document within a collection, use the `edgeFirebase.startDocumentSnapshot(collectionPath, docId)` method.
744
+
745
+ ```javascript
746
+ <script setup>
747
+ edgeFirebase.startDocumentSnapshot("myItems", "exampleDocId");
748
+ </script>
749
+ ```
750
+
751
+ Once you have started a snapshot listener on a document, reactive data for that snapshot will be available with `edgeFirebase.data[collectionPath + '/' + docId]`. This method first checks if the user has read permission for the specified document. If the user has permission, it starts the snapshot listener and updates the reactive data object accordingly. If the user doesn't have permission, it returns an error message indicating the lack of read access.
752
+
753
+
754
+
646
755
  ### Snapshot listeners can also be queried, sorted, and limited.
756
+
647
757
  #### Query and Sort are an array of objects, Limit is a number
648
758
  (if passing more than one query on different keys, FireStore may make you create indexes)
649
759
  ```typescript
@@ -675,7 +785,19 @@ edgeFirebase.stopSnapshot("myItems");
675
785
  </setup>
676
786
  ```
677
787
 
788
+ When stopping a snapshot listener on a specific document within a collection, use the combined `collectionPath + '/' + docId` as the parameter for the `edgeFirebase.stopSnapshot()` method.
789
+
790
+ For example:
791
+
792
+ ```javascript
793
+ <script setup>
794
+ const documentPath = "myItems/exampleDocId";
795
+ edgeFirebase.stopSnapshot(documentPath);
796
+ </script>
797
+ ```
798
+
678
799
  # Firestore Static Collection Data
800
+
679
801
  To get static data from a collection use the Object: **edgeFirebase.SearchStaticData()**. Static search is done from a class to handle pagination better.
680
802
  ```javascript
681
803
  const staticSearch = new edgeFirebase.SearchStaticData();
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@edgedev/firebase",
3
- "version": "1.7.8",
3
+ "version": "1.7.9",
4
4
  "description": "Vue 3 / Nuxt 3 Plugin or Nuxt 3 plugin for firebase authentication and firestore.",
5
5
  "main": "index.ts",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "postinstall": "if [ ! -f ./firestore.rules ]; then echo 'rules_version = \\'2\\';' > ./firestore.rules; else sed -i '1s/^/rules_version = \\'2\\';\\n/' ./firestore.rules; fi && awk '/\/\/ #EDGE FIREBASE RULES START/,/\/\/ #EDGE FIREBASE RULES END/' ./src/firestore.rules | sed 's/\\/\\\\/g; s/&/\\&/g' | sed -e 's/\"/\\\\\"/g' -e 's/\//\\\\\//g' | sed -e '1s/^/\\/\\/ #EDGE FIREBASE RULES START\\n/' -e '$s/$/\\n\\/\\/ #EDGE FIREBASE RULES END/' >> ./firestore.rules"
8
8
  },
9
9
  "author": "Seth Fischer",
10
10
  "keywords": [
@@ -0,0 +1,285 @@
1
+ rules_version = '2';
2
+ service cloud.firestore {
3
+
4
+ match /databases/{database}/documents/events/{event} {
5
+ allow read: if false;
6
+ allow create: if false;
7
+ allow update: if false;
8
+ allow delete: if false;
9
+ }
10
+
11
+ match /databases/{database}/documents/rule-helpers/{helper} {
12
+ allow read: if false;
13
+ allow create: if request.auth.uid == request.resource.data.uid;
14
+ allow update: if request.auth.uid == request.resource.data.uid;
15
+ allow delete: if false;
16
+ }
17
+
18
+ match /databases/{database}/documents/users/{user} {
19
+ function readSelf() {
20
+ return resource == null ||
21
+ (
22
+ "userId" in resource.data &&
23
+ resource.data.userId == request.auth.uid
24
+ );
25
+ }
26
+
27
+ allow read: if readSelf();
28
+ allow create: if false;
29
+ allow update: if false;
30
+ allow delete: if false;
31
+ }
32
+
33
+ match /databases/{database}/documents/collection-data/{collectionPath} {
34
+ // TODO: these rules need tested.
35
+ function getRolePermission(role, collection, permissionCheck) {
36
+ let pathCollectionPermissions = get(/databases/$(database)/documents/collection-data/$(collection)).data;
37
+ let defaultPermissions = get(/databases/$(database)/documents/collection-data/-default-).data;
38
+ return (role in pathCollectionPermissions && pathCollectionPermissions[role][permissionCheck]) ||
39
+ (role in defaultPermissions && defaultPermissions[role][permissionCheck]);
40
+ }
41
+ function canAssign() {
42
+ let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
43
+ let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data['edge-assignment-helper'];
44
+ return collectionPath.matches("^" + ruleHelper[collectionPath].permissionCheckPath + ".*$") &&
45
+ (
46
+ "specialPermissions" in user &&
47
+ ruleHelper[collectionPath].permissionCheckPath in user.specialPermissions &&
48
+ "assign" in user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath] &&
49
+ user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath]["assign"]
50
+ ) ||
51
+ (
52
+ "roles" in user &&
53
+ ruleHelper[collectionPath].permissionCheckPath in user.roles &&
54
+ "role" in user.roles[ruleHelper[collectionPath].permissionCheckPath] &&
55
+ getRolePermission(user.roles[ruleHelper[collectionPath].permissionCheckPath].role, collectionPath, "assign")
56
+ );
57
+ }
58
+ allow read: if request.auth != null; // All signed in users can read collection-data
59
+ allow create: if canAssign();
60
+ allow update: if canAssign();
61
+ allow delete: if canAssign();
62
+ }
63
+
64
+ match /databases/{database}/documents/staged-users/{user} {
65
+
66
+ function canUpdate() {
67
+ let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
68
+ let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
69
+
70
+ return (
71
+ resource == null ||
72
+ request.resource.data.userId == resource.data.userId ||
73
+ (
74
+ resource.data.userId == "" &&
75
+ (
76
+ request.resource.data.userId == request.auth.uid ||
77
+ request.resource.data.templateUserId == request.auth.uid
78
+ )
79
+ )
80
+ ) &&
81
+ "edge-assignment-helper" in ruleHelper &&
82
+ permissionUpdatesCheck(user, ruleHelper, "roles") &&
83
+ permissionUpdatesCheck(user, ruleHelper, "specialPermssions") &&
84
+ request.auth.uid == request.resource.data.uid;
85
+ }
86
+
87
+
88
+ function permissionUpdatesCheck(user, ruleHelper, permissionType) {
89
+ return !(permissionType in request.resource.data) ||
90
+ (
91
+ resource.data.userId == request.auth.uid &&
92
+ request.resource.data[permissionType].keys().hasOnly(resource.data[permissionType].keys())
93
+ ) ||
94
+ (
95
+ resource.data.userId != request.auth.uid &&
96
+ permissionCheck(permissionType, user, ruleHelper)
97
+ );
98
+ }
99
+ function permissionCheck(permissionType, user, ruleHelper) {
100
+ let lastPathUpdated = ruleHelper["edge-assignment-helper"].fullPath;
101
+ let permissionCheckPath = ruleHelper["edge-assignment-helper"].permissionCheckPath;
102
+ return request.resource.data[permissionType].diff(resource.data[permissionType]).affectedKeys().size() == 0 ||
103
+ (
104
+ request.resource.data[permissionType].diff(resource.data[permissionType]).affectedKeys().size() == 1 &&
105
+ request.resource.data[permissionType].diff(resource.data[permissionType]).affectedKeys() == [lastPathUpdated].toSet() &&
106
+ (
107
+ permissionCheckPath == "-" ||
108
+ lastPathUpdated.matches("^" + permissionCheckPath + ".*$")
109
+ ) &&
110
+ (
111
+ (
112
+ "roles" in user &&
113
+ getRolePermission(user.roles[permissionCheckPath].role, permissionCheckPath, "assign")
114
+ ) ||
115
+ (
116
+ "specialPermissions" in user &&
117
+ permissionCheckPath in user.specialPermissions &&
118
+ "assign" in user.specialPermissions[permissionCheckPath] &&
119
+ user.specialPermissions[permissionCheckPath]["assign"]
120
+ )
121
+ )
122
+ );
123
+ }
124
+
125
+ function canAssign(user, ruleHelper) {
126
+ return request.auth != null &&
127
+ "edge-assignment-helper" in ruleHelper &&
128
+ (
129
+ (
130
+ "roles" in user &&
131
+ ruleHelper["edge-assignment-helper"].permissionCheckPath in user.roles &&
132
+ getRolePermission(user.roles[ruleHelper["edge-assignment-helper"].permissionCheckPath].role, ruleHelper["edge-assignment-helper"].permissionCheckPath, 'assign')
133
+ ) ||
134
+ (
135
+ "specialPermissions" in user &&
136
+ ruleHelper["edge-assignment-helper"].permissionCheckPath in user.specialPermissions &&
137
+ "assign" in user.specialPermissions[ruleHelper["edge-assignment-helper"].permissionCheckPath] &&
138
+ user.specialPermissions[ruleHelper["edge-assignment-helper"].permissionCheckPath]["assign"]
139
+ )
140
+ )
141
+ }
142
+
143
+ function canAssignSubCreatePath(user, ruleHelper) {
144
+ let permissionCheckPath = ruleHelper["edge-assignment-helper"].permissionCheckPath;
145
+ return (
146
+ !("subCreate" in request.resource.data) ||
147
+ (
148
+ "subCreate" in request.resource.data &&
149
+ request.resource.data.subCreate.keys().size() == 0
150
+ )
151
+ )||
152
+ (
153
+ permissionCheckPath == "-" ||
154
+ request.resource.data.subCreate.rootPath.matches("^" + permissionCheckPath + ".*$")
155
+ ) &&
156
+ (
157
+ (
158
+ "roles" in user &&
159
+ permissionCheckPath in user.roles &&
160
+ getRolePermission(user.roles[permissionCheckPath].role, permissionCheckPath, "assign")
161
+ ) ||
162
+ (
163
+ "specialPermissions" in user &&
164
+ permissionCheckPath in user.specialPermissions &&
165
+ "assign" in user.specialPermissions[permissionCheckPath] &&
166
+ user.specialPermissions[permissionCheckPath]["assign"]
167
+ )
168
+ )
169
+
170
+ }
171
+
172
+ function canList() {
173
+ let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
174
+ let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
175
+ return canAssign(user, ruleHelper);
176
+ }
177
+
178
+ function canCreate() {
179
+ let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
180
+ let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
181
+ return noPermissionData() && canAssign(user, ruleHelper) && canAssignSubCreatePath(user, ruleHelper);
182
+ }
183
+
184
+ function noPermissionData() {
185
+ return request.resource.data.roles.size() == 0 && request.resource.data.specialPermissions.size() == 0;
186
+ }
187
+
188
+ function getRolePermission(role, collection, permissionCheck) {
189
+ let pathCollectionPermissions = get(/databases/$(database)/documents/collection-data/$(collection)).data;
190
+ let defaultPermissions = get(/databases/$(database)/documents/collection-data/-default-).data;
191
+ return (role in pathCollectionPermissions && pathCollectionPermissions[role][permissionCheck]) ||
192
+ (role in defaultPermissions && defaultPermissions[role][permissionCheck]);
193
+ }
194
+
195
+ function canGet () {
196
+ return resource == null ||
197
+ ("userId" in resource.data && resource.data.userId == "") ||
198
+ ("userId" in resource.data && resource.data.userId == request.auth.uid) ||
199
+ canAssign(get(/databases/$(database)/documents/users/$(request.auth.uid)).data, get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data);
200
+ }
201
+ allow get: if canGet();
202
+ allow list: if canList();
203
+ allow create: if canCreate();
204
+ allow update: if canUpdate();
205
+ allow delete: if false // TODO if isTemplate is true... can delete... otherwise users never deleted just removed from collection paths
206
+ }
207
+
208
+ match /databases/{database}/documents/{seg1} {
209
+ function getRolePermission(role, collection, permissionCheck) {
210
+ let pathCollectionPermissions = get(/databases/$(database)/documents/collection-data/$(collection)).data;
211
+ let defaultPermissions = get(/databases/$(database)/documents/collection-data/-default-).data;
212
+ return (role in pathCollectionPermissions && pathCollectionPermissions[role][permissionCheck]) ||
213
+ (role in defaultPermissions && defaultPermissions[role][permissionCheck]);
214
+ }
215
+ function checkPermission(collectionPath, permissionCheck) {
216
+ let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
217
+ let skipPaths = ["collection-data", "users", "staged-users", "events", "rule-helpers"];
218
+ let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
219
+ return !(collectionPath in skipPaths) &&
220
+ request.auth != null &&
221
+ collectionPath in ruleHelper &&
222
+ "permissionCheckPath" in ruleHelper[collectionPath] &&
223
+ (
224
+ ruleHelper[collectionPath].permissionCheckPath == "-" ||
225
+ collectionPath.matches("^" + ruleHelper[collectionPath].permissionCheckPath + ".*$")
226
+ ) &&
227
+ (
228
+ (
229
+ "roles" in user &&
230
+ ruleHelper[collectionPath].permissionCheckPath in user.roles &&
231
+ getRolePermission(user.roles[ruleHelper[collectionPath].permissionCheckPath].role, ruleHelper[collectionPath].permissionCheckPath, permissionCheck)
232
+ ) ||
233
+ (
234
+ "specialPermissions" in user &&
235
+ ruleHelper[collectionPath].permissionCheckPath in user.specialPermissions &&
236
+ permissionCheck in user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath] &&
237
+ user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath][permissionCheck]
238
+ )
239
+ );
240
+ }
241
+ match /{seg2} {
242
+ allow get: if checkPermission(seg1 + "-" + seg2, "read");
243
+ allow list: if checkPermission(seg1, "read");
244
+ allow create: if checkPermission(seg1, "write");
245
+ allow update: if checkPermission(seg1 + "-" + seg2, "write");
246
+ allow delete: if checkPermission(seg1, "delete");
247
+ match /{seg3} {
248
+ allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
249
+ allow list: if checkPermission(seg1 + "-" + seg2, "read");
250
+ allow create: if checkPermission(seg1 + "-" + seg2, "write");
251
+ allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
252
+ allow delete: if checkPermission(seg1 + "-" + seg2, "delete");
253
+ match /{seg4} {
254
+ allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
255
+ allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
256
+ allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
257
+ allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
258
+ allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "delete");
259
+
260
+ match /{seg5} {
261
+ allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
262
+ allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
263
+ allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
264
+ allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
265
+ allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "delete");
266
+ match /{seg6} {
267
+ allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
268
+ allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
269
+ allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
270
+ allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
271
+ allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "delete");
272
+ match /{seg7} {
273
+ allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "read");
274
+ allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
275
+ allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
276
+ allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "write");
277
+ allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "delete");
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }