@edgedev/firebase 1.3.3 → 1.4.2

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
@@ -242,23 +242,23 @@ edgeFirebase.removeUser("user@edgemarketingdesign.com");
242
242
 
243
243
  ### List Users
244
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.
245
+ This will list all users that are members of collections that the user running the function has assign access for, it will be a listed index by email/user id.
246
246
 
247
247
  ```javascript
248
248
  const users = await edgeFirebase.listUsers();
249
249
  ```
250
250
 
251
251
  ```typescript
252
- interface usersByCollection {
253
- [collectionPath: string]: [user];
252
+ interface usersByEmail {
253
+ [email: string]: [user];
254
254
  }
255
255
  ```
256
256
 
257
257
  ```typescript
258
258
  interface user {
259
259
  email: string;
260
- role: "admin" | "user" | null;
261
- specialPermission: permissions | null;
260
+ roles: {[collectionPath: string ]: "admin" | "user"}
261
+ specialPermissions: {[collectionPath: string]: permissions};
262
262
  userId: string;
263
263
  docId: string;
264
264
  uid: string;
@@ -372,6 +372,30 @@ This function allows a user to change their current password while logged in:
372
372
  edgeFirebase.setPassword("old-password", "new-password");
373
373
  ```
374
374
 
375
+ ### Password Reset:
376
+
377
+ For users not logged in (like forgotten password). This is a two step process if the project is setup to redirect password resets back to a custom password reset page.
378
+
379
+ Step 1:
380
+
381
+ ```javascript
382
+ edgeFirebase.sendPasswordReset('user@edgemarketingdesign.com');
383
+ ```
384
+
385
+ Step 2: (If the password redirect is setup to go a custom page, you'll need to pull the "oobCode" from the query string and pass that along with the newpassword.)
386
+
387
+ ```javascript
388
+ edgeFirebase.passwordReset('NewPassword123','AAaaAABaaaaAAABBBaaaBBBBAaaaaBABAbbaa');
389
+ ```
390
+
391
+ ### Update User Meta:
392
+
393
+ A user can update their own meta data when logged in. The object contain meta data will only update/add the keys passed in the object.
394
+
395
+ ```javascript
396
+ edgeFirebase.setUserMeta({ lastName: "Smith" });
397
+ ```
398
+
375
399
  # Firestore Basic Document Interactions
376
400
 
377
401
  ### Adding/Update a Document.
package/edgeFirebase.ts CHANGED
@@ -36,7 +36,9 @@ import {
36
36
  createUserWithEmailAndPassword,
37
37
  updatePassword,
38
38
  reauthenticateWithCredential,
39
- EmailAuthProvider
39
+ EmailAuthProvider,
40
+ sendPasswordResetEmail,
41
+ confirmPasswordReset
40
42
  } from "firebase/auth";
41
43
 
42
44
  interface FirestoreQuery {
@@ -76,8 +78,6 @@ interface role {
76
78
  role: "admin" | "user";
77
79
  }
78
80
 
79
- // TODO: PASSWORD RESET FUNCTION <-- NOT LOGGED IN, AND USER META UPDATE FUNCTION (ONLY FOR THEMSELVES)
80
-
81
81
  interface specialPermission {
82
82
  collectionPath: "-" | string; // - is root
83
83
  permissions: permissions;
@@ -103,16 +103,16 @@ interface newUser {
103
103
 
104
104
  interface user {
105
105
  email: string;
106
- role: "admin" | "user" | null;
107
- specialPermission: permissions | null;
106
+ roles: {[collectionPath: string ]: "admin" | "user"}
107
+ specialPermissions: {[collectionPath: string]: permissions};
108
108
  userId: string;
109
109
  docId: string;
110
110
  uid: string;
111
111
  last_updated: Date;
112
112
  }
113
113
 
114
- interface usersByCollection {
115
- [collectionPath: string]: [user];
114
+ interface usersByEmail {
115
+ [email: string]: [user];
116
116
  }
117
117
  interface userMeta extends newUser {
118
118
  docId: string;
@@ -314,6 +314,40 @@ export const EdgeFirebase = class {
314
314
  }
315
315
  };
316
316
 
317
+ public sendPasswordReset = async (email: string): Promise<actionResponse> => {
318
+ try {
319
+ await sendPasswordResetEmail(this.auth, email);
320
+ return this.sendResponse({
321
+ success: true,
322
+ message: ""
323
+ });
324
+ } catch (error) {
325
+ return this.sendResponse({
326
+ success: false,
327
+ message: error.message
328
+ });
329
+ }
330
+ };
331
+
332
+ public passwordReset = async (
333
+ password: string,
334
+ oobCode: string
335
+ ): Promise<actionResponse> => {
336
+ try {
337
+ // await verifyPasswordResetCode(this.auth, oobCode);
338
+ await confirmPasswordReset(this.auth, oobCode, password);
339
+ return this.sendResponse({
340
+ success: true,
341
+ message: ""
342
+ });
343
+ } catch (error) {
344
+ return this.sendResponse({
345
+ success: false,
346
+ message: error.message
347
+ });
348
+ }
349
+ };
350
+
317
351
  public setPassword = async (
318
352
  oldpassword: string,
319
353
  password: string
@@ -338,6 +372,18 @@ export const EdgeFirebase = class {
338
372
  }
339
373
  };
340
374
 
375
+ setUserMeta = async (meta: unknown): Promise<actionResponse> => {
376
+ for (const [key, value] of Object.entries(meta)) {
377
+ await updateDoc(doc(this.db, "users/" + this.user.email), {
378
+ ["meta." + key]: value
379
+ });
380
+ }
381
+ return this.sendResponse({
382
+ success: true,
383
+ message: ""
384
+ });
385
+ };
386
+
341
387
  public removeUser = async (email: string): Promise<actionResponse> => {
342
388
  const removedFrom = [];
343
389
  const userRef = doc(this.db, "users", email);
@@ -942,6 +988,7 @@ export const EdgeFirebase = class {
942
988
  }
943
989
  };
944
990
 
991
+ // TODO: change this function to be synced dynamically on the user object
945
992
  public listCollectionsCanAssign = async (): Promise<string[]> => {
946
993
  let collectionPaths = [];
947
994
  for (const role of this.user.roles) {
@@ -989,11 +1036,18 @@ export const EdgeFirebase = class {
989
1036
  return collectionPathList;
990
1037
  };
991
1038
 
992
- public listUsers = async (): Promise<usersByCollection> => {
1039
+ // TODO: finish making this query by collectionPath if passed.. in furture will be used to get users by collectionPath
1040
+ // because having one giant list of users is not scalable
1041
+ public listUsers = async (collectionPath = ''): Promise<usersByEmail> => {
993
1042
  const userList = {};
1043
+ if (collectionPath) {
1044
+ const canAssign = await this.permissionCheck("assign", collectionPath);
1045
+ if (!canAssign) {
1046
+ return {}
1047
+ }
1048
+ }
994
1049
  const collectionPathList = await this.listCollectionsCanAssign();
995
1050
  for (const collectionPath of collectionPathList) {
996
- userList[collectionPath] = [];
997
1051
  const roleUsers = await getDocs(
998
1052
  query(
999
1053
  collection(this.db, "users"),
@@ -1006,16 +1060,20 @@ export const EdgeFirebase = class {
1006
1060
  );
1007
1061
  roleUsers.forEach((doc) => {
1008
1062
  const user = doc.data();
1009
- userList[collectionPath].push({
1010
- docId: user.docId,
1011
- email: user.email,
1012
- role: user.roles[collectionPath].role,
1013
- specialPermission: null,
1014
- meta: user.meta,
1015
- last_updated: user.last_updated,
1016
- userId: user.userId,
1017
- uid: user.uid
1018
- });
1063
+ if (!Object.prototype.hasOwnProperty.call(userList, user.docId)) {
1064
+ userList[user.email] = {
1065
+ docId: user.docId,
1066
+ email: user.email,
1067
+ roles: {[collectionPath]: user.roles[collectionPath].role },
1068
+ specialPermissions: {},
1069
+ meta: user.meta,
1070
+ last_updated: user.last_updated,
1071
+ userId: user.userId,
1072
+ uid: user.uid
1073
+ }
1074
+ } else {
1075
+ userList[user.email].roles[collectionPath] = user.roles[collectionPath].role
1076
+ }
1019
1077
  });
1020
1078
  const specialPermissionsUsers = await getDocs(
1021
1079
  query(
@@ -1029,17 +1087,20 @@ export const EdgeFirebase = class {
1029
1087
  );
1030
1088
  specialPermissionsUsers.forEach((doc) => {
1031
1089
  const user = doc.data();
1032
- userList[collectionPath].push({
1033
- docId: user.docId,
1034
- email: user.email,
1035
- role: null,
1036
- specialPermission:
1037
- user.specialPermissions[collectionPath].permissions,
1038
- meta: user.meta,
1039
- last_updated: user.last_updated,
1040
- userId: user.userId,
1041
- uid: user.uid
1042
- });
1090
+ if (!Object.prototype.hasOwnProperty.call(userList, user.docId)) {
1091
+ userList[user.email] = {
1092
+ docId: user.docId,
1093
+ email: user.email,
1094
+ role: {},
1095
+ specialPermissions: {[collectionPath]: user.specialPermissions[collectionPath].permissions},
1096
+ meta: user.meta,
1097
+ last_updated: user.last_updated,
1098
+ userId: user.userId,
1099
+ uid: user.uid
1100
+ }
1101
+ } else {
1102
+ userList[user.email].specialPermissions[collectionPath] = user.specialPermissions[collectionPath].permissions
1103
+ }
1043
1104
  });
1044
1105
  }
1045
1106
  return userList;
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@edgedev/firebase",
3
- "version": "1.3.3",
3
+ "version": "1.4.2",
4
4
  "description": "Vue 3 / Nuxt 3 Plugin or Nuxt 3 global composable for firebase authentication and firestore.",
5
5
  "main": "index.ts",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
6
9
  "author": "Seth Fischer",
7
10
  "keywords": [
8
11
  "firebase authentication",
@@ -32,8 +35,5 @@
32
35
  "peerDependencies": {
33
36
  "firebase": "^9.12.1",
34
37
  "vue": "^3.0.0"
35
- },
36
- "scripts": {
37
- "test": "echo \"Error: no test specified\" && exit 1"
38
38
  }
39
- }
39
+ }