@firecms/user_management 3.0.0-canary.117 → 3.0.0-canary.119
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/dist/index.es.js +50 -16
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +51 -17
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -5
- package/src/components/roles/RolesDetailsForm.tsx +32 -11
- package/src/hooks/useBuildUserManagement.tsx +33 -8
- package/src/utils/permissions.ts +3 -2
@@ -1,7 +1,7 @@
|
|
1
1
|
import React, { useCallback, useState } from "react";
|
2
2
|
import * as Yup from "yup";
|
3
3
|
|
4
|
-
import { EntityCollection, FieldCaption, Role, toSnakeCase, } from "@firecms/core";
|
4
|
+
import { EntityCollection, FieldCaption, Role, toSnakeCase, useAuthController, User, } from "@firecms/core";
|
5
5
|
import {
|
6
6
|
Button,
|
7
7
|
Checkbox,
|
@@ -30,6 +30,15 @@ export const RoleYupSchema = Yup.object().shape({
|
|
30
30
|
name: Yup.string().required("Required")
|
31
31
|
});
|
32
32
|
|
33
|
+
function canRoleBeEdited(loggedUser: User) {
|
34
|
+
const loggedUserIsAdmin = loggedUser.roles?.map(r => r.id).includes("admin");
|
35
|
+
if (!loggedUserIsAdmin) {
|
36
|
+
throw new Error("Only admins can edit roles");
|
37
|
+
}
|
38
|
+
|
39
|
+
return true;
|
40
|
+
}
|
41
|
+
|
33
42
|
export function RolesDetailsForm({
|
34
43
|
open,
|
35
44
|
role,
|
@@ -46,27 +55,39 @@ export function RolesDetailsForm({
|
|
46
55
|
|
47
56
|
const { saveRole } = useUserManagement();
|
48
57
|
const isNewRole = !role;
|
58
|
+
const {
|
59
|
+
user: loggedInUser
|
60
|
+
} = useAuthController();
|
49
61
|
|
50
62
|
const [savingError, setSavingError] = useState<Error | undefined>();
|
51
63
|
|
52
64
|
const onRoleUpdated = useCallback((role: Role) => {
|
53
65
|
setSavingError(undefined);
|
66
|
+
if (!loggedInUser) throw new Error("User not found");
|
67
|
+
canRoleBeEdited(loggedInUser);
|
54
68
|
return saveRole(role);
|
55
|
-
}, [saveRole]);
|
69
|
+
}, [saveRole, loggedInUser]);
|
56
70
|
|
57
71
|
const formex = useCreateFormex({
|
58
72
|
initialValues: role ?? {
|
59
73
|
name: ""
|
60
74
|
} as Role,
|
61
75
|
onSubmit: (role: Role, formexController) => {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
76
|
+
try {
|
77
|
+
return onRoleUpdated(role)
|
78
|
+
.then(() => {
|
79
|
+
formexController.resetForm({
|
80
|
+
values: role
|
81
|
+
});
|
82
|
+
handleClose();
|
83
|
+
})
|
84
|
+
.catch(e => {
|
85
|
+
setSavingError(e);
|
66
86
|
});
|
67
|
-
|
68
|
-
|
69
|
-
.
|
87
|
+
} catch (e: any) {
|
88
|
+
setSavingError(e);
|
89
|
+
return Promise.resolve();
|
90
|
+
}
|
70
91
|
},
|
71
92
|
validation: (values) => {
|
72
93
|
return RoleYupSchema.validate(values, { abortEarly: false })
|
@@ -397,8 +418,8 @@ export function RolesDetailsForm({
|
|
397
418
|
</DialogContent>
|
398
419
|
|
399
420
|
<DialogActions position={"sticky"}>
|
400
|
-
{savingError && <Typography className={"text-red-500"}>
|
401
|
-
There was an error saving this role
|
421
|
+
{savingError && <Typography className={"text-red-500 dark:text-red-500"}>
|
422
|
+
{savingError.message ?? "There was an error saving this role"}
|
402
423
|
</Typography>}
|
403
424
|
<Button variant={"text"}
|
404
425
|
onClick={() => {
|
@@ -2,10 +2,18 @@ import React, { useCallback, useEffect } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
3
3
|
|
4
4
|
import { UserManagement } from "../types";
|
5
|
-
import {
|
5
|
+
import {
|
6
|
+
Authenticator,
|
7
|
+
DataSourceDelegate,
|
8
|
+
Entity,
|
9
|
+
PermissionsBuilder,
|
10
|
+
removeUndefined,
|
11
|
+
Role,
|
12
|
+
User
|
13
|
+
} from "@firecms/core";
|
6
14
|
import { resolveUserRolePermissions } from "../utils";
|
7
15
|
|
8
|
-
type UserWithRoleIds = User & { roles: string[] };
|
16
|
+
type UserWithRoleIds = Omit<User, "roles"> & { roles: string[] };
|
9
17
|
|
10
18
|
export interface UserManagementParams {
|
11
19
|
|
@@ -90,7 +98,12 @@ export function useBuildUserManagement({
|
|
90
98
|
useEffect(() => {
|
91
99
|
if (!dataSourceDelegate || !rolesPath) return;
|
92
100
|
if (dataSourceDelegate.initialised !== undefined && !dataSourceDelegate.initialised) return;
|
101
|
+
if (dataSourceDelegate.authenticated !== undefined && !dataSourceDelegate.authenticated) {
|
102
|
+
setRolesLoading(false);
|
103
|
+
return;
|
104
|
+
}
|
93
105
|
|
106
|
+
setRolesLoading(true);
|
94
107
|
return dataSourceDelegate.listenCollection?.({
|
95
108
|
path: rolesPath,
|
96
109
|
onUpdate(entities: Entity<any>[]): void {
|
@@ -114,12 +127,17 @@ export function useBuildUserManagement({
|
|
114
127
|
}
|
115
128
|
});
|
116
129
|
|
117
|
-
}, [dataSourceDelegate?.initialised, rolesPath]);
|
130
|
+
}, [dataSourceDelegate?.initialised, dataSourceDelegate?.authenticated, rolesPath]);
|
118
131
|
|
119
132
|
useEffect(() => {
|
120
133
|
if (!dataSourceDelegate || !usersPath) return;
|
121
134
|
if (dataSourceDelegate.initialised !== undefined && !dataSourceDelegate.initialised) return;
|
135
|
+
if (dataSourceDelegate.authenticated !== undefined && !dataSourceDelegate.authenticated) {
|
136
|
+
setUsersLoading(false);
|
137
|
+
return;
|
138
|
+
}
|
122
139
|
|
140
|
+
setUsersLoading(true);
|
123
141
|
return dataSourceDelegate.listenCollection?.({
|
124
142
|
path: usersPath,
|
125
143
|
onUpdate(entities: Entity<any>[]): void {
|
@@ -143,7 +161,7 @@ export function useBuildUserManagement({
|
|
143
161
|
}
|
144
162
|
});
|
145
163
|
|
146
|
-
}, [dataSourceDelegate?.initialised, usersPath]);
|
164
|
+
}, [dataSourceDelegate?.initialised, dataSourceDelegate?.authenticated, usersPath]);
|
147
165
|
|
148
166
|
const saveUser = useCallback(async (user: User): Promise<User> => {
|
149
167
|
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
@@ -154,15 +172,22 @@ export function useBuildUserManagement({
|
|
154
172
|
const roleIds = user.roles?.map(r => r.id);
|
155
173
|
const email = user.email?.toLowerCase().trim();
|
156
174
|
if (!email) throw Error("Email is required");
|
175
|
+
|
176
|
+
const userExists = users.find(u => u.email?.toLowerCase() === email);
|
157
177
|
const data = {
|
158
178
|
...user,
|
159
|
-
roles: roleIds
|
179
|
+
roles: roleIds ?? []
|
160
180
|
};
|
181
|
+
if (!userExists) {
|
182
|
+
// @ts-ignore
|
183
|
+
data.created_on = new Date();
|
184
|
+
}
|
185
|
+
|
161
186
|
return dataSourceDelegate.saveEntity({
|
162
187
|
status: "existing",
|
163
188
|
path: usersPath,
|
164
189
|
entityId: email,
|
165
|
-
values: data
|
190
|
+
values: removeUndefined(data)
|
166
191
|
}).then(() => user);
|
167
192
|
}, [usersPath, dataSourceDelegate?.initialised]);
|
168
193
|
|
@@ -178,7 +203,7 @@ export function useBuildUserManagement({
|
|
178
203
|
status: "existing",
|
179
204
|
path: rolesPath,
|
180
205
|
entityId: id,
|
181
|
-
values: roleData
|
206
|
+
values: removeUndefined(roleData)
|
182
207
|
}).then(() => {
|
183
208
|
return;
|
184
209
|
});
|
@@ -243,7 +268,7 @@ export function useBuildUserManagement({
|
|
243
268
|
}
|
244
269
|
|
245
270
|
throw Error("Could not find a user with the provided email in the user management system.");
|
246
|
-
}, [loading, users]);
|
271
|
+
}, [loading, users, usersError, rolesError]);
|
247
272
|
|
248
273
|
const isAdmin = roles.some(r => r.id === "admin");
|
249
274
|
|
package/src/utils/permissions.ts
CHANGED
@@ -50,8 +50,9 @@ function resolveCollectionRole(role: Role, id: string): Permissions {
|
|
50
50
|
edit: role.isAdmin || role.defaultPermissions?.edit,
|
51
51
|
delete: role.isAdmin || role.defaultPermissions?.delete
|
52
52
|
};
|
53
|
-
|
54
|
-
|
53
|
+
const thisCollectionPermissions = role.collectionPermissions?.[id];
|
54
|
+
if (thisCollectionPermissions) {
|
55
|
+
return mergePermissions(thisCollectionPermissions, basePermissions);
|
55
56
|
} else if (role.defaultPermissions) {
|
56
57
|
return mergePermissions(role.defaultPermissions, basePermissions);
|
57
58
|
} else {
|