@firecms/user_management 3.0.0-canary.13 → 3.0.0-canary.130
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/LICENSE +114 -21
- package/README.md +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/{useBuildFirestoreUserManagement.d.ts → useBuildUserManagement.d.ts} +14 -7
- package/dist/index.es.js +1167 -818
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1635 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/types/user_management.d.ts +14 -3
- package/dist/useUserManagementPlugin.d.ts +6 -1
- package/package.json +12 -28
- package/src/components/roles/RolesDetailsForm.tsx +69 -24
- package/src/components/roles/RolesTable.tsx +6 -4
- package/src/components/roles/RolesView.tsx +3 -1
- package/src/components/users/UserDetailsForm.tsx +11 -9
- package/src/components/users/UsersTable.tsx +6 -4
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useBuildUserManagement.tsx +314 -0
- package/src/types/user_management.tsx +17 -3
- package/src/useUserManagementPlugin.tsx +88 -2
- package/src/utils/permissions.ts +7 -6
- package/src/hooks/useBuildFirestoreUserManagement.tsx +0 -240
@@ -1,240 +0,0 @@
|
|
1
|
-
import React, { useCallback, useEffect, useRef } from "react";
|
2
|
-
import {
|
3
|
-
collection,
|
4
|
-
deleteDoc,
|
5
|
-
doc,
|
6
|
-
DocumentSnapshot,
|
7
|
-
Firestore,
|
8
|
-
getFirestore,
|
9
|
-
onSnapshot,
|
10
|
-
setDoc
|
11
|
-
} from "firebase/firestore";
|
12
|
-
import { FirebaseApp } from "firebase/app";
|
13
|
-
import { UserManagement } from "../types";
|
14
|
-
import { PermissionsBuilder, Role, User } from "@firecms/core";
|
15
|
-
import { resolveUserRolePermissions } from "../utils";
|
16
|
-
|
17
|
-
type UserWithRoleIds = User & { roles: string[] };
|
18
|
-
|
19
|
-
export interface UserManagementParams {
|
20
|
-
/**
|
21
|
-
* The Firebase app to use for the user management. The config will be saved in the Firestore
|
22
|
-
* collection indicated by `configPath`.
|
23
|
-
*/
|
24
|
-
firebaseApp?: FirebaseApp;
|
25
|
-
/**
|
26
|
-
* Path where the plugin users configuration is stored.
|
27
|
-
* Default: __FIRECMS/config/users
|
28
|
-
* You can specify a different path if you want to store the user management configuration in a different place.
|
29
|
-
* 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.
|
31
|
-
*/
|
32
|
-
usersPath?: string;
|
33
|
-
|
34
|
-
/**
|
35
|
-
* Path where the plugin roles configuration is stored.
|
36
|
-
* Default: __FIRECMS/config/roles
|
37
|
-
*/
|
38
|
-
rolesPath?: string;
|
39
|
-
|
40
|
-
usersLimit?: number;
|
41
|
-
|
42
|
-
canEditRoles?: boolean;
|
43
|
-
|
44
|
-
/**
|
45
|
-
* If there are no roles in the database, provide a button to create the default roles.
|
46
|
-
*/
|
47
|
-
allowDefaultRolesCreation?: boolean;
|
48
|
-
|
49
|
-
/**
|
50
|
-
* Include the collection config permissions in the user management system.
|
51
|
-
*/
|
52
|
-
includeCollectionConfigPermissions?: boolean;
|
53
|
-
|
54
|
-
}
|
55
|
-
|
56
|
-
/**
|
57
|
-
* This hook is used to build a user management object that can be used to
|
58
|
-
* manage users and roles in a Firestore backend.
|
59
|
-
* @param backendFirebaseApp
|
60
|
-
* @param usersPath
|
61
|
-
* @param rolesPath
|
62
|
-
* @param usersLimit
|
63
|
-
* @param canEditRoles
|
64
|
-
*/
|
65
|
-
export function useBuildFirestoreUserManagement({
|
66
|
-
firebaseApp,
|
67
|
-
usersPath = "__FIRECMS/config/users",
|
68
|
-
rolesPath = "__FIRECMS/config/roles",
|
69
|
-
usersLimit,
|
70
|
-
canEditRoles = true,
|
71
|
-
allowDefaultRolesCreation,
|
72
|
-
includeCollectionConfigPermissions
|
73
|
-
}: UserManagementParams): UserManagement {
|
74
|
-
|
75
|
-
const firestoreRef = useRef<Firestore>();
|
76
|
-
|
77
|
-
const [rolesLoading, setRolesLoading] = React.useState<boolean>(true);
|
78
|
-
const [usersLoading, setUsersLoading] = React.useState<boolean>(true);
|
79
|
-
const [roles, setRoles] = React.useState<Role[]>([]);
|
80
|
-
const [usersWithRoleIds, setUsersWithRoleIds] = React.useState<UserWithRoleIds[]>([]);
|
81
|
-
|
82
|
-
const users = usersWithRoleIds.map(u => ({
|
83
|
-
...u,
|
84
|
-
roles: roles.filter(r => u.roles?.includes(r.id))
|
85
|
-
}) as User);
|
86
|
-
|
87
|
-
const [rolesError, setRolesError] = React.useState<Error | undefined>();
|
88
|
-
const [usersError, setUsersError] = React.useState<Error | undefined>();
|
89
|
-
|
90
|
-
const loading = rolesLoading || usersLoading;
|
91
|
-
|
92
|
-
useEffect(() => {
|
93
|
-
if (!firebaseApp) return;
|
94
|
-
firestoreRef.current = getFirestore(firebaseApp);
|
95
|
-
}, [firebaseApp]);
|
96
|
-
|
97
|
-
useEffect(() => {
|
98
|
-
if (!firebaseApp || !rolesPath) return;
|
99
|
-
const firestore = getFirestore(firebaseApp);
|
100
|
-
|
101
|
-
return onSnapshot(collection(firestore, rolesPath),
|
102
|
-
{
|
103
|
-
next: (snapshot) => {
|
104
|
-
setRolesError(undefined);
|
105
|
-
try {
|
106
|
-
const newRoles = docsToRoles(snapshot.docs);
|
107
|
-
setRoles(newRoles);
|
108
|
-
} catch (e) {
|
109
|
-
// console.error(e);
|
110
|
-
setRolesError(e as Error);
|
111
|
-
}
|
112
|
-
setRolesLoading(false);
|
113
|
-
},
|
114
|
-
error: (e) => {
|
115
|
-
setRolesError(e);
|
116
|
-
setRolesLoading(false);
|
117
|
-
}
|
118
|
-
}
|
119
|
-
);
|
120
|
-
}, [firebaseApp, rolesPath]);
|
121
|
-
|
122
|
-
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
|
-
setUsersError(e as Error);
|
135
|
-
}
|
136
|
-
setUsersLoading(false);
|
137
|
-
},
|
138
|
-
error: (e) => {
|
139
|
-
setUsersError(e);
|
140
|
-
setUsersLoading(false);
|
141
|
-
}
|
142
|
-
}
|
143
|
-
);
|
144
|
-
}, [firebaseApp, usersPath]);
|
145
|
-
|
146
|
-
const saveUser = useCallback(async (user: User): Promise<User> => {
|
147
|
-
const firestore = firestoreRef.current;
|
148
|
-
if (!firestore || !usersPath) throw Error("useFirestoreConfigurationPersistence Firestore not initialised");
|
149
|
-
console.debug("Persisting user", user);
|
150
|
-
const roleIds = user.roles?.map(r => r.id);
|
151
|
-
const {
|
152
|
-
uid,
|
153
|
-
...userData
|
154
|
-
} = user;
|
155
|
-
return setDoc(doc(firestore, usersPath, uid), {
|
156
|
-
...userData,
|
157
|
-
roles: roleIds
|
158
|
-
}, { merge: true }).then(() => user);
|
159
|
-
}, [usersPath]);
|
160
|
-
|
161
|
-
const saveRole = useCallback((role: Role): Promise<void> => {
|
162
|
-
const firestore = firestoreRef.current;
|
163
|
-
if (!firestore || !rolesPath) throw Error("useFirestoreConfigurationPersistence Firestore not initialised");
|
164
|
-
console.debug("Persisting role", role);
|
165
|
-
const {
|
166
|
-
id,
|
167
|
-
...roleData
|
168
|
-
} = role;
|
169
|
-
const ref = doc(firestore, rolesPath, id);
|
170
|
-
return setDoc(ref, roleData, { merge: true });
|
171
|
-
}, [rolesPath]);
|
172
|
-
|
173
|
-
const deleteUser = useCallback(async (user: User): Promise<void> => {
|
174
|
-
const firestore = firestoreRef.current;
|
175
|
-
if (!firestore || !usersPath) throw Error("useFirestoreConfigurationPersistence Firestore not initialised");
|
176
|
-
console.debug("Deleting", user);
|
177
|
-
const { uid } = user;
|
178
|
-
return deleteDoc(doc(firestore, usersPath, uid));
|
179
|
-
}, [usersPath]);
|
180
|
-
|
181
|
-
const deleteRole = useCallback((role: Role): Promise<void> => {
|
182
|
-
const firestore = firestoreRef.current;
|
183
|
-
if (!firestore || !rolesPath) throw Error("useFirestoreConfigurationPersistence Firestore not initialised");
|
184
|
-
console.debug("Deleting", role);
|
185
|
-
const { id } = role;
|
186
|
-
const ref = doc(firestore, rolesPath, id);
|
187
|
-
return deleteDoc(ref);
|
188
|
-
}, [rolesPath]);
|
189
|
-
|
190
|
-
const collectionPermissions: PermissionsBuilder = useCallback(({
|
191
|
-
collection,
|
192
|
-
user
|
193
|
-
}) => resolveUserRolePermissions({
|
194
|
-
collection,
|
195
|
-
user
|
196
|
-
}), []);
|
197
|
-
|
198
|
-
const userIds = users.map(u => u.uid);
|
199
|
-
const defineRolesFor: ((user: User) => Role[] | undefined) = useCallback((user) => {
|
200
|
-
if (!users) throw Error("Users not loaded");
|
201
|
-
const mgmtUser = users.find(u => u.email?.toLowerCase() === user?.email?.toLowerCase());
|
202
|
-
return mgmtUser?.roles;
|
203
|
-
}, [userIds]);
|
204
|
-
|
205
|
-
return {
|
206
|
-
loading,
|
207
|
-
roles,
|
208
|
-
users,
|
209
|
-
saveUser,
|
210
|
-
saveRole,
|
211
|
-
deleteUser,
|
212
|
-
deleteRole,
|
213
|
-
usersLimit,
|
214
|
-
canEditRoles: canEditRoles === undefined ? true : canEditRoles,
|
215
|
-
allowDefaultRolesCreation: allowDefaultRolesCreation === undefined ? true : allowDefaultRolesCreation,
|
216
|
-
includeCollectionConfigPermissions: Boolean(includeCollectionConfigPermissions),
|
217
|
-
collectionPermissions,
|
218
|
-
defineRolesFor
|
219
|
-
}
|
220
|
-
}
|
221
|
-
|
222
|
-
const docsToUsers = (docs: DocumentSnapshot[]): (UserWithRoleIds)[] => {
|
223
|
-
return docs.map((doc) => {
|
224
|
-
const data = doc.data() as any;
|
225
|
-
const newVar = {
|
226
|
-
uid: doc.id,
|
227
|
-
...data,
|
228
|
-
created_on: data?.created_on?.toDate(),
|
229
|
-
updated_on: data?.updated_on?.toDate()
|
230
|
-
};
|
231
|
-
return newVar as (UserWithRoleIds);
|
232
|
-
});
|
233
|
-
}
|
234
|
-
|
235
|
-
const docsToRoles = (docs: DocumentSnapshot[]): Role[] => {
|
236
|
-
return docs.map((doc) => ({
|
237
|
-
id: doc.id,
|
238
|
-
...doc.data()
|
239
|
-
} as Role));
|
240
|
-
}
|