@edgedev/firebase 1.2.6 → 1.3.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 CHANGED
@@ -4,10 +4,12 @@ A Vue 3 / Nuxt 3 Plugin or Nuxt 3 global composable for firebase authentication
4
4
 
5
5
  ### Table of Contents
6
6
  **[Installation](#installation)**
7
+ **[User Management and Collection Permissions](#user-management-and-collection-permissions)**
7
8
  **[Firebase Authentication](#firebase-authentication)**
8
9
  **[Firestore Basic Document Interactions](#firestore-Basic-document-interactions)**
9
10
  **[Firestore Snapshot Listeners](#firestore-snapshot-listeners)**
10
- **[Firestore Static Collection Data](#firestore-static-collection-data)**
11
+ **[Firestore Static Collection Data](#firestore-static-collection-data)**
12
+ **[Await and response](#await-and-responses)**
11
13
 
12
14
  # Installation
13
15
 
@@ -85,14 +87,197 @@ export default defineNuxtConfig({ ssr: false });
85
87
  ```
86
88
 
87
89
 
88
- #### After installing as a plugin you will need to include this in <script setup> in any component you want to use EdgeFirebase in:
90
+ #### After installing as a plugin you will need to include this in "script setup" in any component you want to use EdgeFirebase in:
89
91
  ```javascript
90
92
  <script setup>
91
93
  import { inject } from "vue";
92
94
  const edgeFirebase = inject("edgeFirebase");
93
95
  </script>
94
96
  ```
97
+
98
+ # User Management and Collection Permissions
99
+
100
+ ### Adding a User
101
+
102
+ Users must be added before they can register with a login and password (the first user in the project will need to be added manual, see the section below "Root permissions and first user"). When adding a user you can pass role and/or special permissions and user meta data. For more explanations on role and special permssions, see below.
103
+
104
+ How to add a user:
105
+
106
+ ```javascript
107
+ edgeFirebase.setUser({
108
+ email: "user@edgemarketingdesign.com",
109
+ roles: [
110
+ {
111
+ collectionPath: "myItems/subitems/things",
112
+ role: "user"
113
+ }
114
+ ],
115
+ specialPermissions: [
116
+ {
117
+ collectionPath: "otherthings",
118
+ permissions: { assign: false, write: true, read: true, delete: false}
119
+ }
120
+ ],
121
+ meta: { firstName: "John", lastName: "Doe", age: 28 } // This is just an example of meta, it can contain any fields and any number of fields.
122
+ });
123
+ ```
124
+
125
+
126
+
127
+ ### Register User
128
+
129
+ After someoene has been added as a user they will need to "self register" to begin using the system. Only users that have been added already by someone with assign permissions can register. The function also checks to make sure they aren't already registered.
130
+
131
+ ```javascript
132
+ edgeFirebase.registerUser({
133
+ email: "user@edgemarketingdesign.com",
134
+ password: "Password1234",
135
+ meta: {
136
+ firstName: "John",
137
+ lastName: "Doe"
138
+ } // This is just an example of meta, it can contain any fields and any number of fields.
139
+ });
140
+ ```
141
+
142
+
143
+
144
+ ### Explanation of permissions
145
+
146
+ - **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.
147
+ - **write: boolean** - Allows a user to write documents to collection
148
+ - **read: boolean** - Allows a user to read documents in a collection
149
+ - **delete: boolean** - Allows a user to delete documents in a collection
150
+
151
+ ### Collection permissions by role
152
+
153
+ Each collection (including sub collections) will automatically have permissions keyed by role. By default each collection and sub collection will receive the following permissions by role when created:
154
+
155
+ - **admin:** assign: true, write: true, read: true, delete: true
156
+ - **user:** assign: false, write:false, read: false, delete: false
157
+
158
+ How to change role permissions for a specific collection:
159
+
160
+ ```javascript
161
+ edgeFirebase.storeCollectionPermissions(
162
+ "myItems/subitems/things", // Collection path
163
+ "user", // must be user or admin
164
+ {
165
+ assign: false,
166
+ write: false,
167
+ read: true,
168
+ delete: false
169
+ }
170
+ );
171
+ ```
172
+
173
+ ### User roles for collections
174
+
175
+ Users are assigned roles based on collection paths. A role assigned by a collection path that has sub collections will also determine what the user can do on all sub collections or a user can be assigned a role specifically for a sub collection only. For example if a user is assigned as admin for "myItems/subitems/things" they will only have admin acces to that collection. But if the user is assigned as an admin for "myItems" they will have the admin permissions for "myItems" and all sub collections of "myItems".
176
+
177
+ How to assign a user a role for a collection:
178
+
179
+ ```javascript
180
+ edgeFirebase.storeUserRoles(
181
+ "user@edgemarketingdesign.com",
182
+ "myItems/subitems/things",
183
+ "admin"
184
+ );
185
+ ```
186
+
187
+ Remove a role from a user for a collection:
188
+
189
+ ```javascript
190
+ edgeFirebase.removeUserRoles(
191
+ "user@edgemarketingdesign.com",
192
+ "myItems/subitems/things"
193
+ );
194
+ ```
195
+
196
+ ### Root permissions and first user
197
+
198
+ 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.
199
+
200
+ | ![root-collection-roles](./images/root-collection-roles.png) | ![root-user](./images/root-user.jpg) |
201
+ | ------------------------------------------------------------ | ------------------------------------ |
202
+
203
+
204
+
205
+ ### User special permissions
206
+
207
+ If you want to give a user a unique set of permissions for a collection that doesn't match the admin or user roles for that collection you can set "special permissions".
208
+
209
+ ```javascript
210
+ edgeFirebase.storeUserSpecialPermissions(
211
+ "user@edgemarketingdesign.com",
212
+ "myItems/subitems/things",
213
+ {
214
+ assign: false,
215
+ write: true,
216
+ read: true,
217
+ delete: true
218
+ }
219
+ );
220
+ ```
221
+
222
+ Remove user special permissions:
223
+
224
+ ```javascript
225
+ edgeFirebase.removeUserSpecialPermissions(
226
+ "user@edgemarketingdesign.com",
227
+ "myItems/subitems/things"
228
+ );
229
+ ```
230
+
231
+
232
+
233
+ ### Remove user
234
+
235
+ The remove user function doesn't actually delete the user completely from the system but instead removes all roles and special permissions that the user running the function has assign access for. In this way the user is "removed" as far as the "assigning user" is concerned but the user will remain a user for collections that the "assign user" doesn't have access to.
236
+
237
+ ```javascript
238
+ edgeFirebase.removeUser("user@edgemarketingdesign.com");
239
+ ```
240
+
241
+
242
+
243
+ ### List Users
244
+
245
+ This will list all users that are members of collections that the user running the function has assign access for, it will list them grouped by collections.
246
+
247
+ ```javascript
248
+ const users = await edgeFirebase.listUsers();
249
+ ```
250
+
251
+ ```typescript
252
+ interface usersByCollection {
253
+ [collectionPath: string]: [user];
254
+ }
255
+ ```
256
+
257
+ ```typescript
258
+ interface user {
259
+ email: string;
260
+ role: "admin" | "user" | null;
261
+ specialPermission: permissions | null;
262
+ userId: string;
263
+ docId: string;
264
+ uid: string;
265
+ last_updated: Date;
266
+ }
267
+ ```
268
+
269
+
270
+
271
+ ### List Collections with Assign Access
272
+
273
+ This function will list all collections that the user running it has assign access for.
274
+
275
+ ```javascript
276
+ const collections = await edgeFirebase.listCollectionsCanAssign(); // returns array of strings (collection paths)
277
+ ```
278
+
95
279
  # Firebase Authentication
280
+
96
281
  (currently only sign in with email and password is supported)
97
282
 
98
283
  If "persistence" is true, login will be saved locally, they can close their browser and when they open they will be logged in automatically. If "persistence" is false login saved only for the session.
@@ -115,6 +300,27 @@ interface UserDataObject {
115
300
  loggedIn: boolean;
116
301
  logInError: boolean;
117
302
  logInErrorMessage: string;
303
+ meta: object;
304
+ roles: role[]; //see role below
305
+ specialPermissions: specialPermission[]; //see specialPermission bleow
306
+ }
307
+
308
+ // sub types of UserDataObject:
309
+ interface role {
310
+ collectionPath: "-" | string; // - is root
311
+ role: "admin" | "user";
312
+ }
313
+
314
+ interface specialPermission {
315
+ collectionPath: "-" | string; // - is root
316
+ permissions: permissions; // see permissions below
317
+ }
318
+
319
+ interface permissions {
320
+ assign: boolean;
321
+ read: boolean;
322
+ write: boolean;
323
+ delete: boolean;
118
324
  }
119
325
  ```
120
326
  The reactive item **edgeFirebase.user.loggedIn** can be used in code or templates to determine if the user is logged in.
@@ -129,7 +335,7 @@ Here is a sample component using the login:
129
335
  <div>
130
336
  <div v-if="edgeFirebase.user.loggedIn">
131
337
  <button @click="edgeFirebase.logOut">Logout</button><br />
132
- <AppUsers v-if="edgeFirebase.user.loggedIn" />
338
+ <ShowThings v-if="edgeFirebase.user.loggedIn" />
133
339
  </div>
134
340
  <div v-else>
135
341
  <input v-model="email" style="width: 400px" type="text" /><br />
@@ -164,8 +370,8 @@ Both adding and updating a document use the same function: **edgeFirebase.store
164
370
 
165
371
  ```javascript
166
372
  <script setup>
167
- const addUser = {name: "bob"};
168
- edgeFirebase.storeDoc("users", addUser);
373
+ const addItem = {title: "Cool Thing"};
374
+ edgeFirebase.storeDoc("myItems", addItem);
169
375
  </script>
170
376
  ```
171
377
  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).
@@ -175,7 +381,7 @@ If you want to query a single document from a collection use: **edgeFirebase.get
175
381
  ```javascript
176
382
  <script setup>
177
383
  const docId = "DrJRpDXVsEEqZu0UB8NT";
178
- const singleDoc = edgeFirebase.getDocData("users", docId);
384
+ const singleDoc = edgeFirebase.getDocData("myItems", docId);
179
385
  </script>
180
386
  ```
181
387
 
@@ -184,7 +390,7 @@ To delete a document use: **edgeFirebase.removeDoc(collectionPath, docId)**
184
390
  ```javascript
185
391
  <script setup>
186
392
  const docId = "DrJRpDXVsEEqZu0UB8NT";
187
- const singleDoc = edgeFirebase.removeDoc("users", docId);
393
+ const singleDoc = edgeFirebase.removeDoc("myItems", docId);
188
394
  </script>
189
395
  ```
190
396
 
@@ -193,15 +399,15 @@ const singleDoc = edgeFirebase.removeDoc("users", docId);
193
399
  To start a snapshot listen on a collection use: **edgeFirebase.startSnapshot(collectionPath)**
194
400
  ```javascript
195
401
  <script setup>
196
- edgeFirebase.startSnapshot("users");
402
+ edgeFirebase.startSnapshot("myItems");
197
403
  </script>
198
404
  ```
199
405
  Once you have started a snapshot reactive data for that snapshot will be available with **edgeFirebase.data[collectionPath]**. Each document in the data object is keyed with the DocumentId from FireStore.
200
406
  ```html
201
407
  <template>
202
408
  <div>
203
- <div v-for="item in edgeFirebase.data.users" :key="item">
204
- {{ item.name }}
409
+ <div v-for="item in edgeFirebase.data.myItems" :key="item">
410
+ {{ item.title }}
205
411
  </div>
206
412
  </div>
207
413
  </template>
@@ -224,17 +430,17 @@ interface FirestoreOrderBy {
224
430
  ##### Example with query, sort and limit:
225
431
  ```javascript
226
432
  <script setup>
227
- const query = [{field: "name", operator: "==", value="Bob"}];
228
- const sort = [{ field: "name", direction: "asc" }];
433
+ const query = [{field: "title", operator: "==", value="Cool Thing"}];
434
+ const sort = [{ field: "title", direction: "asc" }];
229
435
  const limit = 10;
230
- edgeFirebase.startSnapshot("users", query, sort, limit);
436
+ edgeFirebase.startSnapshot("myItems", query, sort, limit);
231
437
  </setup>
232
438
  ```
233
439
  ### Stopping a snapshot listener
234
440
  To stop listening to a collection use: **edgeFirebase.stopSnapshot(collectionPath)**
235
441
  ```javascript
236
442
  <script setup>
237
- edgeFirebase.stopSnapshot("users");
443
+ edgeFirebase.stopSnapshot("myItems");
238
444
  </setup>
239
445
  ```
240
446
 
@@ -242,7 +448,7 @@ edgeFirebase.stopSnapshot("users");
242
448
  To get static data from a collection use the Object: **edgeFirebase.SearchStaticData()**. Static search is done from a class to handle pagination better.
243
449
  ```javascript
244
450
  const staticSearch = new edgeFirebase.SearchStaticData();
245
- staticSearch.getData("users");
451
+ staticSearch.getData("myItems");
246
452
  ```
247
453
  After initialized like above... Data will be available from **staticSearch.results.data**
248
454
 
@@ -271,7 +477,7 @@ for updating **staticSearch.results.data** the pagination data set. There are a
271
477
  <template>
272
478
  <div>
273
479
  <div v-for="item in staticSearch.results.data" :key="item">
274
- {{ item.name }}
480
+ {{ item.title }}
275
481
  </div>
276
482
  <div>
277
483
  <button
@@ -294,12 +500,34 @@ for updating **staticSearch.results.data** the pagination data set. There are a
294
500
  <script setup>
295
501
  const staticSearch = new edgeFirebase.SearchStaticData();
296
502
 
297
- const query = [{field: "name", operator: "==", value="Bob"}];
298
- const sort = [{ field: "name", direction: "asc" }];
503
+ const query = [{field: "title", operator: "==", value="Cool Thing"}];
504
+ const sort = [{ field: "title", direction: "asc" }];
299
505
  const limit = 10;
300
506
 
301
- staticSearch.getData("users", query, sort, limit);
507
+ staticSearch.getData("myItems", query, sort, limit);
302
508
  </script>
303
509
  ```
510
+
511
+
512
+ # Await and responses
513
+
514
+ All functions can be used in conjunction with "await" and will return a response that can be used.
515
+
516
+ ```javascript
517
+ const response = await edgeFirebase.startSnapshot("things");
518
+ ```
519
+
520
+ reponse:
521
+
522
+ ```typescript
523
+ interface actionResponse {
524
+ success: boolean;
525
+ message: string;
526
+ }
527
+ ```
528
+
529
+
530
+
304
531
  ## License
532
+
305
533
  [ISC](https://choosealicense.com/licenses/isc/)