@driveflux/auth 4.0.86 → 4.0.87
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/AuthProvider.js +76 -59
- package/dist/authorization/constants.js +45 -24
- package/dist/authorization/define.js +57 -28
- package/dist/authorization/fields/index.js +4 -7
- package/dist/authorization/helpers.js +10 -8
- package/dist/authorization/index.js +6 -6
- package/dist/authorization/permissions-list.js +5 -7
- package/dist/authorization/quick.js +1 -1
- package/dist/authorization/roles/admin/business-development-executive.js +20 -7
- package/dist/authorization/roles/admin/ceo.js +4 -2
- package/dist/authorization/roles/admin/common.js +5 -3
- package/dist/authorization/roles/admin/concierge.js +35 -10
- package/dist/authorization/roles/admin/customer-success-executive.js +40 -10
- package/dist/authorization/roles/admin/data-analyst.js +7 -4
- package/dist/authorization/roles/admin/designer.js +7 -4
- package/dist/authorization/roles/admin/engineer.js +7 -4
- package/dist/authorization/roles/admin/finance-executive.js +11 -4
- package/dist/authorization/roles/admin/head-of-business-development.js +14 -4
- package/dist/authorization/roles/admin/head-of-data-analytics.js +14 -4
- package/dist/authorization/roles/admin/head-of-engineering.js +17 -6
- package/dist/authorization/roles/admin/head-of-finance.js +8 -3
- package/dist/authorization/roles/admin/head-of-human-resources.js +13 -5
- package/dist/authorization/roles/admin/head-of-marketing.js +17 -5
- package/dist/authorization/roles/admin/head-of-operations.js +8 -3
- package/dist/authorization/roles/admin/head-of-product.js +17 -6
- package/dist/authorization/roles/admin/head-of-sales.js +17 -5
- package/dist/authorization/roles/admin/human-resources-executive.js +12 -5
- package/dist/authorization/roles/admin/marketing-executive.js +7 -4
- package/dist/authorization/roles/admin/product-manager.js +7 -4
- package/dist/authorization/roles/admin/sales-executive.js +24 -8
- package/dist/authorization/roles/consumer/business-admin.js +19 -6
- package/dist/authorization/roles/consumer/business-user.js +18 -6
- package/dist/authorization/roles/consumer/member.js +16 -6
- package/dist/authorization/types.js +1 -1
- package/dist/authorization/update-user-permissions.js +22 -15
- package/dist/authorization/utils.js +26 -11
- package/dist/constants.js +2 -4
- package/dist/context.js +8 -9
- package/dist/default.js +1 -1
- package/dist/server/authenticate-user.js +11 -7
- package/dist/server/cors.js +23 -12
- package/dist/server/credentials-provider.js +2 -2
- package/dist/server/next-auth.js +104 -109
- package/dist/server/prisma-adapter.js +88 -52
- package/dist/server/verfiy-token.js +39 -24
- package/dist/translations.js +4 -4
- package/dist/use-auth.js +1 -1
- package/dist/use-session.js +1 -1
- package/package.json +2 -2
package/dist/AuthProvider.js
CHANGED
|
@@ -8,37 +8,34 @@ import Cookies from 'js-cookie';
|
|
|
8
8
|
//! seems like bad idea but it's the only way to resolve conflict
|
|
9
9
|
//! between Vercel build and reference of NextRouter instance
|
|
10
10
|
import Router, { useRouter } from 'next/dist/client/router.js';
|
|
11
|
-
import { useCallback, useEffect, useMemo, useRef, useState
|
|
11
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
12
|
import useSWR from 'swr';
|
|
13
13
|
import { AuthContext } from './context.js';
|
|
14
14
|
import { translations } from './translations.js';
|
|
15
|
-
const AuthProvider = ({ children })
|
|
15
|
+
const AuthProvider = ({ children })=>{
|
|
16
16
|
const { data: session, status, update } = useAuthSession();
|
|
17
17
|
const { setUserData } = useTrackEvent();
|
|
18
18
|
const [token, setToken] = useState(null);
|
|
19
19
|
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const newTokenPromise = useRef(null);
|
|
20
|
+
* A reference to a promise that fetches a new access token from the server.
|
|
21
|
+
* This is used to prevent multiple token requests from being sent simultaneously.
|
|
22
|
+
*/ const newTokenPromise = useRef(null);
|
|
24
23
|
const localeLogicRan = useRef(false);
|
|
25
24
|
const router = useRouter();
|
|
26
25
|
const { pathname, asPath, query, locale } = router;
|
|
27
26
|
const { toastResult } = useToastResult();
|
|
28
|
-
const { data: user, isValidating, mutate, error
|
|
29
|
-
fallbackData: session
|
|
30
|
-
?.user,
|
|
27
|
+
const { data: user, isValidating, mutate, error } = useSWR(session ? `${config.apiUrl}/user` : null, {
|
|
28
|
+
fallbackData: session?.user
|
|
31
29
|
});
|
|
32
30
|
const isLoadingUser = status !== 'unauthenticated' && isValidating && !user;
|
|
33
31
|
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const getAccessToken = useCallback(async () => {
|
|
32
|
+
* Retrieves an access token for the current user. If a token is already available and has not expired, it will be returned immediately.
|
|
33
|
+
* Otherwise, the function will attempt to retrieve the token from cookies, and if that fails, it will fetch a new token from the server.
|
|
34
|
+
* If a new token is fetched, it will be stored in cookies and returned.
|
|
35
|
+
* If the user is not authenticated, the function will return null and display an error message.
|
|
36
|
+
* @returns {Promise<string | null>} A promise that resolves to the access token string, or null if the user is not authenticated.
|
|
37
|
+
*/ // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
|
38
|
+
const getAccessToken = useCallback(async ()=>{
|
|
42
39
|
// Check the state first, if we have a token, return it
|
|
43
40
|
if (token && token.expiresAt > new Date()) {
|
|
44
41
|
return token.accessToken;
|
|
@@ -51,19 +48,17 @@ const AuthProvider = ({ children }) => {
|
|
|
51
48
|
if (expiresAt > new Date()) {
|
|
52
49
|
setToken({
|
|
53
50
|
accessToken: tokenFromCookies.accessToken,
|
|
54
|
-
expiresAt
|
|
51
|
+
expiresAt
|
|
55
52
|
});
|
|
56
53
|
}
|
|
57
54
|
return tokenFromCookies.accessToken;
|
|
58
55
|
}
|
|
56
|
+
} catch (_e) {
|
|
57
|
+
// TODO
|
|
58
|
+
// Nothing to do here
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Nothing to do here
|
|
63
|
-
}
|
|
64
|
-
const tokenPromise = newTokenPromise.current ||
|
|
65
|
-
// biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
|
|
66
|
-
(newTokenPromise.current = enhancedFetch(`${config.apiUrl}/user/token`));
|
|
60
|
+
const tokenPromise = newTokenPromise.current || // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
|
|
61
|
+
(newTokenPromise.current = enhancedFetch(`${config.apiUrl}/user/token`));
|
|
67
62
|
// As a last resort, fetch a new token
|
|
68
63
|
const newToken = await tokenPromise;
|
|
69
64
|
// Resets the newTokenPromise reference to null after the new token has been fetched.
|
|
@@ -72,42 +67,50 @@ const AuthProvider = ({ children }) => {
|
|
|
72
67
|
toastResult(newToken, {
|
|
73
68
|
error: {
|
|
74
69
|
title: translations.unauthenticated,
|
|
75
|
-
description: translations.unauthenticatedDescription
|
|
76
|
-
}
|
|
70
|
+
description: translations.unauthenticatedDescription
|
|
71
|
+
}
|
|
77
72
|
});
|
|
78
73
|
return null;
|
|
79
74
|
}
|
|
80
75
|
const newTokenDetils = {
|
|
81
76
|
accessToken: newToken.val.id,
|
|
82
|
-
expiresAt: new Date(newToken.val.expiresAt)
|
|
77
|
+
expiresAt: new Date(newToken.val.expiresAt)
|
|
83
78
|
};
|
|
84
79
|
Cookies.set('accessTokenDetails', JSON.stringify(newTokenDetils));
|
|
85
80
|
setToken(newTokenDetils);
|
|
86
81
|
return newToken.val.id;
|
|
87
|
-
}, [
|
|
88
|
-
|
|
82
|
+
}, [
|
|
83
|
+
token
|
|
84
|
+
]);
|
|
85
|
+
const refresh = useCallback(async ()=>{
|
|
89
86
|
await update();
|
|
90
87
|
return await mutate();
|
|
91
|
-
}, [
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
}, [
|
|
89
|
+
mutate,
|
|
90
|
+
update
|
|
91
|
+
]);
|
|
92
|
+
const logout = useCallback(async ()=>{
|
|
93
|
+
await signOut({
|
|
94
|
+
redirect: false
|
|
95
|
+
});
|
|
94
96
|
await refresh();
|
|
95
|
-
}, [
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
97
|
+
}, [
|
|
98
|
+
refresh
|
|
99
|
+
]);
|
|
100
|
+
const context = useMemo(()=>({
|
|
101
|
+
user,
|
|
102
|
+
isLoadingUser,
|
|
103
|
+
refresh,
|
|
104
|
+
error,
|
|
105
|
+
getAccessToken,
|
|
106
|
+
// TODO
|
|
107
|
+
/**
|
|
108
|
+
* @deprecated do not use this property, use getAccessToken instead
|
|
109
|
+
*/ accessToken: token?.accessToken,
|
|
110
|
+
signIn,
|
|
111
|
+
logout,
|
|
112
|
+
status
|
|
113
|
+
}), [
|
|
111
114
|
user,
|
|
112
115
|
isLoadingUser,
|
|
113
116
|
refresh,
|
|
@@ -115,11 +118,11 @@ const AuthProvider = ({ children }) => {
|
|
|
115
118
|
getAccessToken,
|
|
116
119
|
logout,
|
|
117
120
|
token,
|
|
118
|
-
status
|
|
121
|
+
status
|
|
119
122
|
]);
|
|
120
123
|
// Add preferredLocal if any
|
|
121
124
|
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
|
122
|
-
useEffect(()
|
|
125
|
+
useEffect(()=>{
|
|
123
126
|
if (localeLogicRan.current || !user) {
|
|
124
127
|
return;
|
|
125
128
|
}
|
|
@@ -127,23 +130,37 @@ const AuthProvider = ({ children }) => {
|
|
|
127
130
|
const langFromCookies = Cookies.get('NEXT_LOCALE');
|
|
128
131
|
if (user?.preferredLocale && langFromCookies !== user?.preferredLocale) {
|
|
129
132
|
Cookies.set('NEXT_LOCALE', user.preferredLocale);
|
|
130
|
-
Router.push({
|
|
133
|
+
Router.push({
|
|
134
|
+
pathname,
|
|
135
|
+
query
|
|
136
|
+
}, asPath, {
|
|
137
|
+
locale: user.preferredLocale
|
|
138
|
+
});
|
|
131
139
|
}
|
|
132
|
-
}, [
|
|
140
|
+
}, [
|
|
141
|
+
user?.preferredLocale,
|
|
142
|
+
pathname,
|
|
143
|
+
query,
|
|
144
|
+
asPath
|
|
145
|
+
]);
|
|
133
146
|
// Add user to the tracking
|
|
134
147
|
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
|
135
|
-
useEffect(()
|
|
136
|
-
if (!user)
|
|
137
|
-
return;
|
|
148
|
+
useEffect(()=>{
|
|
149
|
+
if (!user) return;
|
|
138
150
|
setUserData({
|
|
139
151
|
id: user.id,
|
|
140
152
|
email: user.email,
|
|
141
153
|
phoneNumber: user.phoneNumber,
|
|
142
154
|
firstName: user.firstName,
|
|
143
155
|
lastName: user.lastName,
|
|
144
|
-
addresses: user.addresses
|
|
156
|
+
addresses: user.addresses
|
|
145
157
|
});
|
|
146
|
-
}, [
|
|
147
|
-
|
|
158
|
+
}, [
|
|
159
|
+
user
|
|
160
|
+
]);
|
|
161
|
+
return /*#__PURE__*/ _jsx(AuthContext.Provider, {
|
|
162
|
+
value: context,
|
|
163
|
+
children: children
|
|
164
|
+
});
|
|
148
165
|
};
|
|
149
166
|
export default AuthProvider;
|
|
@@ -6,7 +6,7 @@ export const DEPARTMENTS = {
|
|
|
6
6
|
SALES: 'sales',
|
|
7
7
|
FINANCE: 'finance',
|
|
8
8
|
DATA_ANALYTICS: 'dataAnalytics',
|
|
9
|
-
PRODUCT: 'product'
|
|
9
|
+
PRODUCT: 'product'
|
|
10
10
|
};
|
|
11
11
|
export const ROLES = {
|
|
12
12
|
CEO: 'ceo',
|
|
@@ -32,43 +32,54 @@ export const ROLES = {
|
|
|
32
32
|
PRODUCT_MANAGER: 'productManager',
|
|
33
33
|
MEMBER: 'member',
|
|
34
34
|
BUSINESS_ADMIN: 'businessAdmin',
|
|
35
|
-
BUSINESS_USER: 'businessUser'
|
|
35
|
+
BUSINESS_USER: 'businessUser'
|
|
36
36
|
};
|
|
37
37
|
export const DEPARTMENTS_MAP = {
|
|
38
38
|
[DEPARTMENTS.CEO_OFFICE]: [
|
|
39
39
|
ROLES.CEO,
|
|
40
40
|
ROLES.HEAD_OF_HUMAN_RESOURCES,
|
|
41
|
-
ROLES.HUMAN_RESOURCES_EXECUTIVE
|
|
41
|
+
ROLES.HUMAN_RESOURCES_EXECUTIVE
|
|
42
42
|
],
|
|
43
43
|
[DEPARTMENTS.OPERATIONS]: [
|
|
44
44
|
ROLES.HEAD_OF_OPERATIONS,
|
|
45
45
|
ROLES.CUSTOMER_SUCCESS_EXECUTIVE,
|
|
46
|
-
ROLES.CONCIERGE
|
|
46
|
+
ROLES.CONCIERGE
|
|
47
|
+
],
|
|
48
|
+
[DEPARTMENTS.MARKETING]: [
|
|
49
|
+
ROLES.HEAD_OF_MARKETING,
|
|
50
|
+
ROLES.MARKETING_EXECUTIVE
|
|
47
51
|
],
|
|
48
|
-
[DEPARTMENTS.MARKETING]: [ROLES.HEAD_OF_MARKETING, ROLES.MARKETING_EXECUTIVE],
|
|
49
52
|
[DEPARTMENTS.BUSINESS_DEVELOPMENT]: [
|
|
50
53
|
ROLES.HEAD_OF_BUSINESS_DEVELOPMENT,
|
|
51
|
-
ROLES.BUSINESS_DEVELOPMENT_EXECUTIVE
|
|
54
|
+
ROLES.BUSINESS_DEVELOPMENT_EXECUTIVE
|
|
55
|
+
],
|
|
56
|
+
[DEPARTMENTS.SALES]: [
|
|
57
|
+
ROLES.HEAD_OF_SALES,
|
|
58
|
+
ROLES.SALES_EXECUTIVE
|
|
59
|
+
],
|
|
60
|
+
[DEPARTMENTS.FINANCE]: [
|
|
61
|
+
ROLES.HEAD_OF_FINANCE,
|
|
62
|
+
ROLES.FINANCE_EXECUTIVE
|
|
52
63
|
],
|
|
53
|
-
[DEPARTMENTS.SALES]: [ROLES.HEAD_OF_SALES, ROLES.SALES_EXECUTIVE],
|
|
54
|
-
[DEPARTMENTS.FINANCE]: [ROLES.HEAD_OF_FINANCE, ROLES.FINANCE_EXECUTIVE],
|
|
55
64
|
[DEPARTMENTS.DATA_ANALYTICS]: [
|
|
56
65
|
ROLES.HEAD_OF_DATA_ANALYTICS,
|
|
57
|
-
ROLES.DATA_ANALYST
|
|
66
|
+
ROLES.DATA_ANALYST
|
|
58
67
|
],
|
|
59
68
|
[DEPARTMENTS.PRODUCT]: [
|
|
60
69
|
ROLES.HEAD_OF_PRODUCT,
|
|
61
70
|
ROLES.HEAD_OF_ENGINEERING,
|
|
62
71
|
ROLES.DESIGNER,
|
|
63
72
|
ROLES.ENGINEER,
|
|
64
|
-
ROLES.PRODUCT_MANAGER
|
|
65
|
-
]
|
|
73
|
+
ROLES.PRODUCT_MANAGER
|
|
74
|
+
]
|
|
66
75
|
};
|
|
67
|
-
export const OWNER_ROLES = [
|
|
76
|
+
export const OWNER_ROLES = [
|
|
77
|
+
ROLES.CEO
|
|
78
|
+
];
|
|
68
79
|
export const HIGHER_ADMIN_ROLES = [
|
|
69
80
|
ROLES.HEAD_OF_HUMAN_RESOURCES,
|
|
70
81
|
ROLES.HEAD_OF_PRODUCT,
|
|
71
|
-
ROLES.HEAD_OF_ENGINEERING
|
|
82
|
+
ROLES.HEAD_OF_ENGINEERING
|
|
72
83
|
];
|
|
73
84
|
export const ADMIN_ROLES = [
|
|
74
85
|
...HIGHER_ADMIN_ROLES,
|
|
@@ -88,28 +99,38 @@ export const ADMIN_ROLES = [
|
|
|
88
99
|
ROLES.DATA_ANALYST,
|
|
89
100
|
ROLES.DESIGNER,
|
|
90
101
|
ROLES.ENGINEER,
|
|
91
|
-
ROLES.PRODUCT_MANAGER
|
|
102
|
+
ROLES.PRODUCT_MANAGER
|
|
103
|
+
];
|
|
104
|
+
export const ALL_ADMIN_ROLES = [
|
|
105
|
+
...ADMIN_ROLES,
|
|
106
|
+
...OWNER_ROLES
|
|
92
107
|
];
|
|
93
|
-
export const ALL_ADMIN_ROLES = [...ADMIN_ROLES, ...OWNER_ROLES];
|
|
94
108
|
export const BUSINESS_ROLES = [
|
|
95
109
|
ROLES.BUSINESS_ADMIN,
|
|
96
|
-
ROLES.BUSINESS_USER
|
|
110
|
+
ROLES.BUSINESS_USER
|
|
111
|
+
];
|
|
112
|
+
export const CONSUMER_ROLES = [
|
|
113
|
+
...BUSINESS_ROLES,
|
|
114
|
+
ROLES.MEMBER
|
|
115
|
+
];
|
|
116
|
+
export const ASSIGNABLE_ROLES = [
|
|
117
|
+
...ADMIN_ROLES,
|
|
118
|
+
...CONSUMER_ROLES
|
|
97
119
|
];
|
|
98
|
-
export const CONSUMER_ROLES = [...BUSINESS_ROLES, ROLES.MEMBER];
|
|
99
|
-
export const ASSIGNABLE_ROLES = [...ADMIN_ROLES, ...CONSUMER_ROLES];
|
|
100
120
|
/**
|
|
101
121
|
* This is to make it easier for some libraries like zod to understand
|
|
102
122
|
* the roles types. Keep this in sync with the above ROLES constant
|
|
103
|
-
*/
|
|
104
|
-
|
|
123
|
+
*/ export const GENERAL_ROLES = [
|
|
124
|
+
...ALL_ADMIN_ROLES,
|
|
125
|
+
...CONSUMER_ROLES
|
|
126
|
+
];
|
|
105
127
|
export const GUEST_PERMISSIONS = [
|
|
106
128
|
{
|
|
107
129
|
action: 'create',
|
|
108
|
-
subject: 'Inquiry'
|
|
130
|
+
subject: 'Inquiry'
|
|
109
131
|
},
|
|
110
132
|
{
|
|
111
133
|
action: 'read',
|
|
112
|
-
subject: 'Vehicle'
|
|
113
|
-
|
|
114
|
-
},
|
|
134
|
+
subject: 'Vehicle'
|
|
135
|
+
}
|
|
115
136
|
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AbilityBuilder } from '@casl/ability';
|
|
2
2
|
import { createPrismaAbility } from '@casl/prisma';
|
|
3
|
-
import { ALL_ADMIN_ROLES, CONSUMER_ROLES, GENERAL_ROLES, HIGHER_ADMIN_ROLES, OWNER_ROLES
|
|
3
|
+
import { ALL_ADMIN_ROLES, CONSUMER_ROLES, GENERAL_ROLES, HIGHER_ADMIN_ROLES, OWNER_ROLES } from './constants.js';
|
|
4
4
|
import { defineRoleAbilitiesBusinessDevelopmentExecutive } from './roles/admin/business-development-executive.js';
|
|
5
5
|
import { defineRoleAbilitiesCeo } from './roles/admin/ceo.js';
|
|
6
6
|
import { defineRoleAbilitiesCommonAdmin } from './roles/admin/common.js';
|
|
@@ -26,45 +26,64 @@ import { defineRoleAbilitiesSalesExecutive } from './roles/admin/sales-executive
|
|
|
26
26
|
import { defineRoleAbilitiesBusinessAdmin } from './roles/consumer/business-admin.js';
|
|
27
27
|
import { defineRoleAbilitiesBusinessUser } from './roles/consumer/business-user.js';
|
|
28
28
|
import { defineRoleAbilitiesMember } from './roles/consumer/member.js';
|
|
29
|
-
export const defineAbilityFor = async (user)
|
|
29
|
+
export const defineAbilityFor = async (user)=>{
|
|
30
30
|
const { can, cannot, build } = new AbilityBuilder(createPrismaAbility);
|
|
31
31
|
if (!user) {
|
|
32
32
|
return build();
|
|
33
33
|
}
|
|
34
|
-
const groups = Array.isArray(user.groups)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
const groups = Array.isArray(user.groups) ? user.groups.map((r)=>`${r}`) : typeof user.groups === 'string' ? [
|
|
35
|
+
user.groups
|
|
36
|
+
] : [];
|
|
37
|
+
const consumerGroups = groups.filter((g)=>CONSUMER_ROLES.includes(g));
|
|
38
|
+
const adminGroups = groups.filter((g)=>!consumerGroups.includes(g));
|
|
39
|
+
const sortedGroups = [
|
|
40
|
+
...consumerGroups,
|
|
41
|
+
...adminGroups
|
|
42
|
+
];
|
|
43
|
+
for (const role of sortedGroups){
|
|
43
44
|
await defineSpecificRoleAbilities(role, can, cannot, user);
|
|
44
45
|
}
|
|
45
46
|
// Common admin abilities
|
|
46
|
-
if (user.groups.some((g)
|
|
47
|
+
if (user.groups.some((g)=>adminGroups.includes(g))) {
|
|
47
48
|
await defineRoleAbilitiesCommonAdmin(can);
|
|
48
49
|
}
|
|
49
50
|
// General abilities
|
|
50
|
-
can([
|
|
51
|
-
|
|
51
|
+
can([
|
|
52
|
+
'read',
|
|
53
|
+
'update'
|
|
54
|
+
], 'User', {
|
|
55
|
+
id: user.id
|
|
56
|
+
});
|
|
57
|
+
can([
|
|
58
|
+
'read'
|
|
59
|
+
], 'Invoice', {
|
|
60
|
+
payerId: user.id
|
|
61
|
+
});
|
|
52
62
|
if (user.businessId) {
|
|
53
|
-
can([
|
|
63
|
+
can([
|
|
64
|
+
'read'
|
|
65
|
+
], 'Invoice', {
|
|
66
|
+
payerId: user.businessId
|
|
67
|
+
});
|
|
54
68
|
}
|
|
55
|
-
can('reserveVehicle', 'User', {
|
|
69
|
+
can('reserveVehicle', 'User', {
|
|
70
|
+
banned: false,
|
|
71
|
+
consented: true
|
|
72
|
+
});
|
|
56
73
|
// Prevent updating the groups for all users
|
|
57
|
-
cannot('update', 'User', [
|
|
74
|
+
cannot('update', 'User', [
|
|
75
|
+
'groups'
|
|
76
|
+
]);
|
|
58
77
|
return build();
|
|
59
78
|
};
|
|
60
|
-
const defineSpecificRoleAbilities = async (r, can, cannot, rawUser)
|
|
79
|
+
const defineSpecificRoleAbilities = async (r, can, cannot, rawUser)=>{
|
|
61
80
|
if (!~GENERAL_ROLES.indexOf(r)) {
|
|
62
81
|
return;
|
|
63
82
|
}
|
|
64
83
|
// Type issue
|
|
65
84
|
const user = rawUser;
|
|
66
85
|
const role = r;
|
|
67
|
-
switch
|
|
86
|
+
switch(role){
|
|
68
87
|
// Owners
|
|
69
88
|
case 'ceo':
|
|
70
89
|
defineRoleAbilitiesCeo(can);
|
|
@@ -142,20 +161,30 @@ const defineSpecificRoleAbilities = async (r, can, cannot, rawUser) => {
|
|
|
142
161
|
case 'businessAdmin':
|
|
143
162
|
defineRoleAbilitiesBusinessAdmin(can, user);
|
|
144
163
|
break;
|
|
145
|
-
default:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
164
|
+
default:
|
|
165
|
+
{
|
|
166
|
+
const _exhaustiveCheck = role;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
149
169
|
}
|
|
150
|
-
if (![
|
|
170
|
+
if (![
|
|
171
|
+
...OWNER_ROLES,
|
|
172
|
+
...HIGHER_ADMIN_ROLES
|
|
173
|
+
].includes(role)) {
|
|
151
174
|
cannot('manageAdmin', 'User');
|
|
152
|
-
cannot([
|
|
175
|
+
cannot([
|
|
176
|
+
'create',
|
|
177
|
+
'update',
|
|
178
|
+
'delete'
|
|
179
|
+
], 'User', undefined, {
|
|
153
180
|
groups: {
|
|
154
|
-
hasSome: [
|
|
155
|
-
|
|
181
|
+
hasSome: [
|
|
182
|
+
...ALL_ADMIN_ROLES
|
|
183
|
+
]
|
|
184
|
+
}
|
|
156
185
|
}).because('You are not allowed to update admin users');
|
|
157
186
|
can('update', 'User', undefined, {
|
|
158
|
-
id: user.id
|
|
187
|
+
id: user.id
|
|
159
188
|
});
|
|
160
189
|
}
|
|
161
190
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Prisma, prisma } from '@driveflux/db';
|
|
2
|
-
export const MODEL_FIELDS = Object.keys(Prisma.ModelName)
|
|
3
|
-
.map((k) => {
|
|
2
|
+
export const MODEL_FIELDS = Object.keys(Prisma.ModelName).map((k)=>{
|
|
4
3
|
if (!(k in Prisma.ModelName)) {
|
|
5
4
|
return null;
|
|
6
5
|
}
|
|
@@ -8,17 +7,15 @@ export const MODEL_FIELDS = Object.keys(Prisma.ModelName)
|
|
|
8
7
|
return {
|
|
9
8
|
// TODO
|
|
10
9
|
// @ts-expect-error
|
|
11
|
-
[key]: prisma._runtimeDataModel.models[key].fields.map((f)
|
|
10
|
+
[key]: prisma._runtimeDataModel.models[key].fields.map((f)=>f.name)
|
|
12
11
|
};
|
|
13
|
-
})
|
|
14
|
-
.filter((m) => m)
|
|
15
|
-
.reduce((carry, current) => {
|
|
12
|
+
}).filter((m)=>m).reduce((carry, current)=>{
|
|
16
13
|
if (current) {
|
|
17
14
|
Object.assign(carry, current);
|
|
18
15
|
}
|
|
19
16
|
return carry;
|
|
20
17
|
}, {});
|
|
21
|
-
export const getModelFields = (model)
|
|
18
|
+
export const getModelFields = (model)=>{
|
|
22
19
|
const fields = MODEL_FIELDS[model];
|
|
23
20
|
return fields;
|
|
24
21
|
};
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { ALL_ADMIN_ROLES, CONSUMER_ROLES, OWNER_ROLES } from './constants';
|
|
2
|
-
export const extractAdminRoles = (userGroups)
|
|
3
|
-
return userGroups?.filter((group)
|
|
2
|
+
export const extractAdminRoles = (userGroups)=>{
|
|
3
|
+
return userGroups?.filter((group)=>isAdmin(group));
|
|
4
4
|
};
|
|
5
|
-
export const extractNonAdminRoles = (userGroups)
|
|
6
|
-
return userGroups?.filter((group)
|
|
5
|
+
export const extractNonAdminRoles = (userGroups)=>{
|
|
6
|
+
return userGroups?.filter((group)=>!isAdmin(group));
|
|
7
7
|
};
|
|
8
|
-
export const isConsumer = (group)
|
|
8
|
+
export const isConsumer = (group)=>{
|
|
9
9
|
return CONSUMER_ROLES.includes(group);
|
|
10
10
|
};
|
|
11
|
-
export const isOwner = (group)
|
|
12
|
-
return [
|
|
11
|
+
export const isOwner = (group)=>{
|
|
12
|
+
return [
|
|
13
|
+
...OWNER_ROLES
|
|
14
|
+
]?.map((r)=>group === r)?.[0];
|
|
13
15
|
};
|
|
14
|
-
export const isAdmin = (group)
|
|
16
|
+
export const isAdmin = (group)=>{
|
|
15
17
|
return ALL_ADMIN_ROLES.includes(group);
|
|
16
18
|
};
|
|
@@ -4,15 +4,15 @@ import { ErrorWithResult } from '@driveflux/result';
|
|
|
4
4
|
import { GUEST_PERMISSIONS } from './constants.js';
|
|
5
5
|
import buildAbilityFromJson from './quick.js';
|
|
6
6
|
import { updateUserPermissions } from './update-user-permissions.js';
|
|
7
|
-
export const buildOrDefineAbility = async (user, refresh)
|
|
7
|
+
export const buildOrDefineAbility = async (user, refresh)=>{
|
|
8
8
|
if (!user) {
|
|
9
|
-
return createPrismaAbility([
|
|
10
|
-
|
|
9
|
+
return createPrismaAbility([
|
|
10
|
+
...GUEST_PERMISSIONS
|
|
11
|
+
], {
|
|
12
|
+
detectSubjectType: detectSubjectType
|
|
11
13
|
});
|
|
12
14
|
}
|
|
13
|
-
if (!Array.isArray(user.permissions) ||
|
|
14
|
-
!user.permissions?.length ||
|
|
15
|
-
refresh) {
|
|
15
|
+
if (!Array.isArray(user.permissions) || !user.permissions?.length || refresh) {
|
|
16
16
|
const result = await updateUserPermissions(user);
|
|
17
17
|
if (result.err) {
|
|
18
18
|
throw new ErrorWithResult(result);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { s } from './utils.js';
|
|
2
|
-
export const getPermissionsFromAbility = (ability)
|
|
2
|
+
export const getPermissionsFromAbility = (ability)=>{
|
|
3
3
|
return {
|
|
4
4
|
// Lists
|
|
5
5
|
viewContractsList: ability.can('read', 'SubscriptionContract'),
|
|
@@ -53,7 +53,7 @@ export const getPermissionsFromAbility = (ability) => {
|
|
|
53
53
|
updateVehicleServiceCenters: ability.can('update', 'Vehicle', 'allowedServiceCenterIds'),
|
|
54
54
|
readPricingInput: ability.can('readPricingInput', 'Vehicle'),
|
|
55
55
|
updatePricingInput: ability.can('update', 'Vehicle', 'pricing'),
|
|
56
|
-
testPricingInput: ability.can('testPricingInput', 'Vehicle'),
|
|
56
|
+
testPricingInput: ability.can('testPricingInput', 'Vehicle'),
|
|
57
57
|
// Users ( Members )
|
|
58
58
|
createMember: ability.can('create', 'User'),
|
|
59
59
|
updateMember: ability.can('update', s('User')),
|
|
@@ -84,8 +84,7 @@ export const getPermissionsFromAbility = (ability) => {
|
|
|
84
84
|
updateInvoice: ability.can('update', s('Invoice', 'payerId')),
|
|
85
85
|
cancelInvoice: ability.can('cancelInvoice', 'Invoice'),
|
|
86
86
|
markInvoiceAsPaid: ability.can('markInvoice', 'Invoice', 'paid'),
|
|
87
|
-
markInvoiceAsRefunded: ability.can('markInvoice', 'Invoice', 'totalRefunded') &&
|
|
88
|
-
ability.can('create', 'Refund'),
|
|
87
|
+
markInvoiceAsRefunded: ability.can('markInvoice', 'Invoice', 'totalRefunded') && ability.can('create', 'Refund'),
|
|
89
88
|
readPaymentMethodsUser: ability.can('read', s('User'), 'paymentMethods'),
|
|
90
89
|
readPaymentMethodsBusiness: ability.can('read', s('Business'), 'paymentMethods'),
|
|
91
90
|
addPaymentMethodUser: ability.can('update', s('User'), 'paymentMethods'),
|
|
@@ -133,8 +132,7 @@ export const getPermissionsFromAbility = (ability) => {
|
|
|
133
132
|
// TODO add logs permision or remove the comments
|
|
134
133
|
// Logs
|
|
135
134
|
// Website Settings
|
|
136
|
-
uploadBanners: ability.can('update', 'PlatformConfig') &&
|
|
137
|
-
ability.can('create', 'PlatformConfig'),
|
|
135
|
+
uploadBanners: ability.can('update', 'PlatformConfig') && ability.can('create', 'PlatformConfig'),
|
|
138
136
|
deleteBanners: ability.can('update', 'PlatformConfig'),
|
|
139
137
|
// Quotations
|
|
140
138
|
createQuotation: ability.can('create', 'Quotation'),
|
|
@@ -143,6 +141,6 @@ export const getPermissionsFromAbility = (ability) => {
|
|
|
143
141
|
createVacancy: ability.can('create', 'Vacancy'),
|
|
144
142
|
updateVacancy: ability.can('update', 'Vacancy'),
|
|
145
143
|
readApplicant: ability.can('read', 'Applicant'),
|
|
146
|
-
readVacancy: ability.can('read', 'Vacancy')
|
|
144
|
+
readVacancy: ability.can('read', 'Vacancy')
|
|
147
145
|
};
|
|
148
146
|
};
|
|
@@ -2,7 +2,7 @@ import { createPrismaAbility } from '@casl/prisma';
|
|
|
2
2
|
import { detectSubjectType } from './utils.js';
|
|
3
3
|
export function buildAbilityFromJson(user) {
|
|
4
4
|
return createPrismaAbility(user.permissions, {
|
|
5
|
-
detectSubjectType
|
|
5
|
+
detectSubjectType
|
|
6
6
|
});
|
|
7
7
|
}
|
|
8
8
|
export default buildAbilityFromJson;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getDocumentsFields } from '../../utils.js';
|
|
2
|
-
export const defineRoleAbilitiesBusinessDevelopmentExecutive = async (can, cannot)
|
|
2
|
+
export const defineRoleAbilitiesBusinessDevelopmentExecutive = async (can, cannot)=>{
|
|
3
3
|
can('read', [
|
|
4
4
|
'Subscription',
|
|
5
5
|
'Vehicle',
|
|
@@ -13,22 +13,35 @@ export const defineRoleAbilitiesBusinessDevelopmentExecutive = async (can, canno
|
|
|
13
13
|
'PaymentLink',
|
|
14
14
|
'Invoice',
|
|
15
15
|
'Transaction',
|
|
16
|
-
'Refund'
|
|
16
|
+
'Refund'
|
|
17
17
|
]);
|
|
18
18
|
cannot('update', 'Invoice');
|
|
19
|
-
can('manage', [
|
|
19
|
+
can('manage', [
|
|
20
|
+
'Vehicle',
|
|
21
|
+
'ServiceCenter',
|
|
22
|
+
'Host',
|
|
23
|
+
'Inquiry',
|
|
24
|
+
'Token'
|
|
25
|
+
]);
|
|
20
26
|
can('readPricingInput', 'Vehicle');
|
|
21
27
|
can('connectHostToStripe', 'Host');
|
|
22
|
-
can('update', 'Subscription', [
|
|
28
|
+
can('update', 'Subscription', [
|
|
29
|
+
'vehicleId'
|
|
30
|
+
]);
|
|
23
31
|
cannot('read', 'User', 'status');
|
|
24
32
|
cannot('read', 'User', [
|
|
25
33
|
...getDocumentsFields('identification'),
|
|
26
34
|
...getDocumentsFields('drivingHistory'),
|
|
27
35
|
...getDocumentsFields('financial'),
|
|
28
|
-
...getDocumentsFields('offerLetter')
|
|
36
|
+
...getDocumentsFields('offerLetter')
|
|
37
|
+
]);
|
|
38
|
+
can([
|
|
39
|
+
'viewSubscriptionApproval'
|
|
40
|
+
], 'Subscription');
|
|
41
|
+
cannot('read', [
|
|
42
|
+
'Vacancy',
|
|
43
|
+
'Applicant'
|
|
29
44
|
]);
|
|
30
|
-
can(['viewSubscriptionApproval'], 'Subscription');
|
|
31
|
-
cannot('read', ['Vacancy', 'Applicant']);
|
|
32
45
|
can('read', 'Activity');
|
|
33
46
|
can('read', 'ActivityTask');
|
|
34
47
|
};
|