@firecms/user_management 3.0.0-canary.84 → 3.0.0-canary.85

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.
@@ -1,33 +1,23 @@
1
1
  import React, { useCallback, useEffect } from "react";
2
- import {
3
- addDoc,
4
- collection,
5
- deleteDoc,
6
- doc,
7
- DocumentSnapshot,
8
- getFirestore,
9
- onSnapshot,
10
- setDoc
11
- } from "@firebase/firestore";
12
- import { FirebaseApp } from "@firebase/app";
13
2
  import { UserManagement } from "../types";
14
- import { Authenticator, PermissionsBuilder, Role, User } from "@firecms/core";
3
+ import { Authenticator, DataSourceDelegate, Entity, PermissionsBuilder, Role, User } from "@firecms/core";
15
4
  import { resolveUserRolePermissions } from "../utils";
16
5
 
17
6
  type UserWithRoleIds = User & { roles: string[] };
18
7
 
19
8
  export interface UserManagementParams {
9
+
20
10
  /**
21
- * The Firebase app to use for the user management. The config will be saved in the Firestore
22
- * collection indicated by `configPath`.
11
+ * The delegate in charge of persisting the data.
23
12
  */
24
- firebaseApp?: FirebaseApp;
13
+ dataSourceDelegate?: DataSourceDelegate;
14
+
25
15
  /**
26
16
  * Path where the plugin users configuration is stored.
27
17
  * Default: __FIRECMS/config/users
28
18
  * You can specify a different path if you want to store the user management configuration in a different place.
29
19
  * Please keep in mind that the FireCMS users are not necessarily the same as the Firebase users (but they can be).
30
- * The path should be relative to the root of the Firestore database, and should always have an odd number of segments.
20
+ * The path should be relative to the root of the database, and should always have an odd number of segments.
31
21
  */
32
22
  usersPath?: string;
33
23
 
@@ -62,14 +52,14 @@ export interface UserManagementParams {
62
52
  /**
63
53
  * This hook is used to build a user management object that can be used to
64
54
  * manage users and roles in a Firestore backend.
65
- * @param backendFirebaseApp
55
+ * @param dataSourceDelegate
66
56
  * @param usersPath
67
57
  * @param rolesPath
68
58
  * @param usersLimit
69
59
  * @param canEditRoles
70
60
  */
71
- export function useFirestoreUserManagement({
72
- firebaseApp,
61
+ export function useBuildUserManagement({
62
+ dataSourceDelegate,
73
63
  usersPath = "__FIRECMS/config/users",
74
64
  rolesPath = "__FIRECMS/config/roles",
75
65
  usersLimit,
@@ -94,62 +84,61 @@ export function useFirestoreUserManagement({
94
84
  const loading = rolesLoading || usersLoading;
95
85
 
96
86
  useEffect(() => {
97
- if (!firebaseApp || !rolesPath) return;
98
- const firestore = getFirestore(firebaseApp);
99
-
100
- return onSnapshot(collection(firestore, rolesPath),
101
- {
102
- next: (snapshot) => {
103
- setRolesError(undefined);
104
- try {
105
- const newRoles = docsToRoles(snapshot.docs);
106
- setRoles(newRoles);
107
- } catch (e) {
108
- console.error("Error loading roles", e);
109
- setRolesError(e as Error);
110
- }
111
- setRolesLoading(false);
112
- },
113
- error: (e) => {
87
+ if (!dataSourceDelegate || !rolesPath) return;
88
+
89
+ dataSourceDelegate.listenCollection?.({
90
+ path: rolesPath,
91
+ onUpdate(entities: Entity<any>[]): void {
92
+ setRolesError(undefined);
93
+ try {
94
+ const newRoles = entityToRoles(entities);
95
+ setRoles(newRoles);
96
+ } catch (e) {
114
97
  console.error("Error loading roles", e);
115
- setRolesError(e);
116
- setRolesLoading(false);
98
+ setRolesError(e as Error);
117
99
  }
100
+ setRolesLoading(false);
101
+ },
102
+ onError(e: any): void {
103
+ console.error("Error loading roles", e);
104
+ setRolesError(e);
105
+ setRolesLoading(false);
118
106
  }
119
- );
120
- }, [firebaseApp, rolesPath]);
107
+ });
108
+
109
+ }, [dataSourceDelegate, rolesPath]);
121
110
 
122
111
  useEffect(() => {
123
- if (!firebaseApp || !usersPath) return;
124
- const firestore = getFirestore(firebaseApp);
125
-
126
- return onSnapshot(collection(firestore, usersPath),
127
- {
128
- next: (snapshot) => {
129
- setUsersError(undefined);
130
- try {
131
- const newUsers = docsToUsers(snapshot.docs);
132
- setUsersWithRoleIds(newUsers);
133
- } catch (e) {
134
- console.error("Error loading users", e);
135
- setUsersError(e as Error);
136
- }
137
- setUsersLoading(false);
138
- },
139
- error: (e) => {
112
+ if (!dataSourceDelegate || !usersPath) return;
113
+
114
+ dataSourceDelegate.listenCollection?.({
115
+ path: usersPath,
116
+ onUpdate(entities: Entity<any>[]): void {
117
+ setUsersError(undefined);
118
+ try {
119
+ const newUsers = entitiesToUsers(entities);
120
+ setUsersWithRoleIds(newUsers);
121
+ } catch (e) {
140
122
  console.error("Error loading users", e);
141
- setUsersError(e);
142
- setUsersLoading(false);
123
+ setUsersError(e as Error);
143
124
  }
125
+ setUsersLoading(false);
126
+ },
127
+ onError(e: any): void {
128
+ console.error("Error loading users", e);
129
+ setUsersError(e);
130
+ setUsersLoading(false);
144
131
  }
145
- );
146
- }, [firebaseApp, usersPath]);
132
+ });
133
+
134
+ }, [dataSourceDelegate, usersPath]);
147
135
 
148
136
  const saveUser = useCallback(async (user: User): Promise<User> => {
149
- if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
150
- const firestore = getFirestore(firebaseApp);
151
- if (!firestore || !usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
137
+ if (!dataSourceDelegate) throw Error("useFirestoreUserManagement Firebase not initialised");
138
+ if (!usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
139
+
152
140
  console.debug("Persisting user", user);
141
+
153
142
  const roleIds = user.roles?.map(r => r.id);
154
143
  const {
155
144
  uid,
@@ -160,43 +149,64 @@ export function useFirestoreUserManagement({
160
149
  roles: roleIds
161
150
  };
162
151
  if (uid) {
163
- return setDoc(doc(firestore, usersPath, uid), data, { merge: true }).then(() => user);
152
+ return dataSourceDelegate.saveEntity({
153
+ status: "existing",
154
+ path: usersPath,
155
+ entityId: uid,
156
+ values: data
157
+ }).then(() => user);
164
158
  } else {
165
- return addDoc(collection(firestore, usersPath), data).then(() => user);
159
+ return dataSourceDelegate.saveEntity({
160
+ status: "new",
161
+ path: usersPath,
162
+ values: data
163
+ }).then(() => user);
166
164
  }
167
- }, [usersPath, firebaseApp]);
165
+ }, [usersPath, dataSourceDelegate]);
168
166
 
169
167
  const saveRole = useCallback((role: Role): Promise<void> => {
170
- if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
171
- const firestore = getFirestore(firebaseApp);
172
- if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
168
+ if (!dataSourceDelegate) throw Error("useFirestoreUserManagement Firebase not initialised");
169
+ if (!rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
173
170
  console.debug("Persisting role", role);
174
171
  const {
175
172
  id,
176
173
  ...roleData
177
174
  } = role;
178
- const ref = doc(firestore, rolesPath, id);
179
- return setDoc(ref, roleData, { merge: true });
180
- }, [rolesPath, firebaseApp]);
175
+ return dataSourceDelegate.saveEntity({
176
+ status: "existing",
177
+ path: rolesPath,
178
+ entityId: id,
179
+ values: roleData
180
+ }).then(() => {
181
+ return;
182
+ });
183
+ }, [rolesPath, dataSourceDelegate]);
181
184
 
182
185
  const deleteUser = useCallback(async (user: User): Promise<void> => {
183
- if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
184
- const firestore = getFirestore(firebaseApp);
185
- if (!firestore || !usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
186
+ if (!dataSourceDelegate) throw Error("useFirestoreUserManagement Firebase not initialised");
187
+ if (!usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
186
188
  console.debug("Deleting", user);
187
189
  const { uid } = user;
188
- return deleteDoc(doc(firestore, usersPath, uid));
189
- }, [usersPath, firebaseApp]);
190
+ const entity: Entity<any> = {
191
+ path: usersPath,
192
+ id: uid,
193
+ values: {}
194
+ };
195
+ await dataSourceDelegate.deleteEntity({ entity })
196
+ }, [usersPath, dataSourceDelegate]);
190
197
 
191
- const deleteRole = useCallback((role: Role): Promise<void> => {
192
- if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
193
- const firestore = getFirestore(firebaseApp);
194
- if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
198
+ const deleteRole = useCallback(async (role: Role): Promise<void> => {
199
+ if (!dataSourceDelegate) throw Error("useFirestoreUserManagement Firebase not initialised");
200
+ if (!rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
195
201
  console.debug("Deleting", role);
196
202
  const { id } = role;
197
- const ref = doc(firestore, rolesPath, id);
198
- return deleteDoc(ref);
199
- }, [rolesPath, firebaseApp]);
203
+ const entity: Entity<any> = {
204
+ path: usersPath,
205
+ id: id,
206
+ values: {}
207
+ };
208
+ await dataSourceDelegate.deleteEntity({ entity })
209
+ }, [rolesPath, dataSourceDelegate]);
200
210
 
201
211
  const collectionPermissions: PermissionsBuilder = useCallback(({
202
212
  collection,
@@ -256,22 +266,22 @@ export function useFirestoreUserManagement({
256
266
  }
257
267
  }
258
268
 
259
- const docsToUsers = (docs: DocumentSnapshot[]): (UserWithRoleIds)[] => {
269
+ const entitiesToUsers = (docs: Entity<Omit<UserWithRoleIds, "id">>[]): (UserWithRoleIds)[] => {
260
270
  return docs.map((doc) => {
261
- const data = doc.data() as any;
271
+ const data = doc.values as any;
262
272
  const newVar = {
263
273
  uid: doc.id,
264
274
  ...data,
265
- created_on: data?.created_on?.toDate(),
266
- updated_on: data?.updated_on?.toDate()
275
+ created_on: data?.created_on,
276
+ updated_on: data?.updated_on
267
277
  };
268
278
  return newVar as (UserWithRoleIds);
269
279
  });
270
280
  }
271
281
 
272
- const docsToRoles = (docs: DocumentSnapshot[]): Role[] => {
273
- return docs.map((doc) => ({
282
+ const entityToRoles = (entities: Entity<Omit<Role, "id">>[]): Role[] => {
283
+ return entities.map((doc) => ({
274
284
  id: doc.id,
275
- ...doc.data()
285
+ ...doc.values
276
286
  } as Role));
277
287
  }