@edgedev/firebase 1.2.5 → 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 +248 -20
- package/edgeFirebase.ts +904 -102
- package/images/root-collection-roles.png +0 -0
- package/images/root-user.jpg +0 -0
- package/package.json +6 -6
- package/pnpm-lock.yaml +1993 -0
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# @edgedev/firebase
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Vue 3 / Nuxt 3 Plugin or Nuxt 3 global composable for firebase authentication and firestore.
|
|
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
|
|
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
|
+
|  |  |
|
|
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
|
-
<
|
|
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
|
|
168
|
-
edgeFirebase.storeDoc("
|
|
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("
|
|
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("
|
|
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("
|
|
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.
|
|
204
|
-
{{ item.
|
|
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: "
|
|
228
|
-
const sort = [{ field: "
|
|
433
|
+
const query = [{field: "title", operator: "==", value="Cool Thing"}];
|
|
434
|
+
const sort = [{ field: "title", direction: "asc" }];
|
|
229
435
|
const limit = 10;
|
|
230
|
-
edgeFirebase.startSnapshot("
|
|
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("
|
|
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("
|
|
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.
|
|
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: "
|
|
298
|
-
const sort = [{ field: "
|
|
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("
|
|
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/)
|