@flusys/nestjs-shared 3.0.0-rc → 3.0.1
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 +851 -275
- package/cjs/classes/api-controller.class.js +4 -4
- package/cjs/constants/permissions.js +34 -11
- package/cjs/decorators/require-permission.decorator.js +7 -3
- package/cjs/enums/index.js +20 -0
- package/cjs/enums/notification-type.enum.js +17 -0
- package/cjs/enums/participant-status.enum.js +17 -0
- package/cjs/enums/recurrence-type.enum.js +18 -0
- package/cjs/exceptions/permission.exception.js +2 -2
- package/cjs/guards/permission.guard.js +66 -65
- package/cjs/index.js +1 -0
- package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
- package/cjs/interfaces/index.js +2 -0
- package/cjs/interfaces/notification-adapter.interface.js +11 -0
- package/cjs/interfaces/permission.interface.js +1 -1
- package/cjs/utils/html-sanitizer.util.js +9 -9
- package/cjs/utils/request.util.js +2 -1
- package/classes/api-controller.class.d.ts +3 -3
- package/constants/permissions.d.ts +36 -0
- package/decorators/require-permission.decorator.d.ts +3 -2
- package/enums/index.d.ts +3 -0
- package/enums/notification-type.enum.d.ts +6 -0
- package/enums/participant-status.enum.d.ts +6 -0
- package/enums/recurrence-type.enum.d.ts +7 -0
- package/exceptions/permission.exception.d.ts +1 -1
- package/fesm/classes/api-controller.class.js +5 -5
- package/fesm/constants/permissions.js +28 -14
- package/fesm/decorators/require-permission.decorator.js +18 -65
- package/fesm/enums/index.js +3 -0
- package/fesm/enums/notification-type.enum.js +7 -0
- package/fesm/enums/participant-status.enum.js +7 -0
- package/fesm/enums/recurrence-type.enum.js +8 -0
- package/fesm/exceptions/permission.exception.js +2 -2
- package/fesm/guards/permission.guard.js +66 -65
- package/fesm/index.js +1 -0
- package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
- package/fesm/interfaces/index.js +2 -0
- package/fesm/interfaces/notification-adapter.interface.js +1 -0
- package/fesm/interfaces/permission.interface.js +1 -3
- package/fesm/utils/request.util.js +2 -1
- package/guards/permission.guard.d.ts +2 -4
- package/index.d.ts +1 -0
- package/interfaces/event-manager-adapter.interface.d.ts +43 -0
- package/interfaces/index.d.ts +2 -0
- package/interfaces/notification-adapter.interface.d.ts +22 -0
- package/interfaces/permission.interface.d.ts +13 -8
- package/package.json +7 -2
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Centralized Permission Codes
|
|
3
|
-
*
|
|
4
|
-
* Single source of truth for all permission codes used across the application.
|
|
5
|
-
* Use these constants instead of hardcoded strings to prevent typos and enable easy refactoring.
|
|
6
|
-
*
|
|
7
|
-
* Naming Convention: <entity>.<action>
|
|
8
|
-
* - entity: The resource being accessed (e.g., user, role, company)
|
|
9
|
-
* - action: The operation being performed (create, read, update, delete, assign)
|
|
10
|
-
*/ // ==================== AUTH MODULE ====================
|
|
1
|
+
// ==================== AUTH MODULE ====================
|
|
11
2
|
export const USER_PERMISSIONS = {
|
|
12
3
|
CREATE: 'user.create',
|
|
13
4
|
READ: 'user.read',
|
|
@@ -100,10 +91,28 @@ export const FORM_RESULT_PERMISSIONS = {
|
|
|
100
91
|
UPDATE: 'form-result.update',
|
|
101
92
|
DELETE: 'form-result.delete'
|
|
102
93
|
};
|
|
94
|
+
// ==================== EVENT MANAGER MODULE ====================
|
|
95
|
+
export const EVENT_PERMISSIONS = {
|
|
96
|
+
CREATE: 'event.create',
|
|
97
|
+
READ: 'event.read',
|
|
98
|
+
UPDATE: 'event.update',
|
|
99
|
+
DELETE: 'event.delete'
|
|
100
|
+
};
|
|
101
|
+
export const EVENT_PARTICIPANT_PERMISSIONS = {
|
|
102
|
+
CREATE: 'event-participant.create',
|
|
103
|
+
READ: 'event-participant.read',
|
|
104
|
+
UPDATE: 'event-participant.update',
|
|
105
|
+
DELETE: 'event-participant.delete'
|
|
106
|
+
};
|
|
107
|
+
// ==================== NOTIFICATION MODULE ====================
|
|
108
|
+
export const NOTIFICATION_PERMISSIONS = {
|
|
109
|
+
CREATE: 'notification.create',
|
|
110
|
+
READ: 'notification.read',
|
|
111
|
+
UPDATE: 'notification.update',
|
|
112
|
+
DELETE: 'notification.delete'
|
|
113
|
+
};
|
|
103
114
|
// ==================== AGGREGATED EXPORTS ====================
|
|
104
|
-
|
|
105
|
-
* All permission codes grouped by module
|
|
106
|
-
*/ export const PERMISSIONS = {
|
|
115
|
+
export const PERMISSIONS = {
|
|
107
116
|
// Auth
|
|
108
117
|
USER: USER_PERMISSIONS,
|
|
109
118
|
COMPANY: COMPANY_PERMISSIONS,
|
|
@@ -124,5 +133,10 @@ export const FORM_RESULT_PERMISSIONS = {
|
|
|
124
133
|
EMAIL_TEMPLATE: EMAIL_TEMPLATE_PERMISSIONS,
|
|
125
134
|
// Form Builder
|
|
126
135
|
FORM: FORM_PERMISSIONS,
|
|
127
|
-
FORM_RESULT: FORM_RESULT_PERMISSIONS
|
|
136
|
+
FORM_RESULT: FORM_RESULT_PERMISSIONS,
|
|
137
|
+
// Event Manager
|
|
138
|
+
EVENT: EVENT_PERMISSIONS,
|
|
139
|
+
EVENT_PARTICIPANT: EVENT_PARTICIPANT_PERMISSIONS,
|
|
140
|
+
// Notification
|
|
141
|
+
NOTIFICATION: NOTIFICATION_PERMISSIONS
|
|
128
142
|
};
|
|
@@ -1,75 +1,28 @@
|
|
|
1
1
|
import { SetMetadata } from '@nestjs/common';
|
|
2
2
|
import { PERMISSIONS_KEY } from '../constants';
|
|
3
|
-
/**
|
|
4
|
-
* Decorator to require specific permissions for a route
|
|
5
|
-
*
|
|
6
|
-
* By default uses AND logic (user must have ALL permissions).
|
|
7
|
-
* This is the most common and secure pattern.
|
|
8
|
-
*
|
|
9
|
-
* @param permissions - One or more permission keys required (AND logic)
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* // Require single permission
|
|
13
|
-
* @RequirePermission('users.read')
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* // Require ALL permissions (AND)
|
|
17
|
-
* @RequirePermission('users.read', 'users.write')
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* // For OR logic, use RequireAnyPermission instead
|
|
21
|
-
* @RequireAnyPermission('admin.access', 'manager.access')
|
|
22
|
-
*/ export const RequirePermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
|
|
3
|
+
/** Require ALL permissions (AND logic) - most secure pattern */ export const RequirePermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
|
|
23
4
|
permissions,
|
|
24
|
-
operator: '
|
|
5
|
+
operator: 'AND'
|
|
25
6
|
});
|
|
26
|
-
/**
|
|
27
|
-
* Decorator to require ANY of the specified permissions (OR logic)
|
|
28
|
-
*
|
|
29
|
-
* User must have at least ONE of the specified permissions.
|
|
30
|
-
* Less secure than RequirePermission (AND), use carefully.
|
|
31
|
-
*
|
|
32
|
-
* @param permissions - User must have at least ONE of these permissions
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* @RequireAnyPermission('admin.access', 'manager.access')
|
|
36
|
-
*/ export const RequireAnyPermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
|
|
7
|
+
/** Require ANY permission (OR logic) - use carefully */ export const RequireAnyPermission = (...permissions)=>SetMetadata(PERMISSIONS_KEY, {
|
|
37
8
|
permissions,
|
|
38
|
-
operator: '
|
|
9
|
+
operator: 'OR'
|
|
39
10
|
});
|
|
40
11
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* Supports building complex permission trees:
|
|
44
|
-
* - AND/OR operators
|
|
45
|
-
* - Nested children for complex logic
|
|
46
|
-
*
|
|
47
|
-
* @param condition - Complex permission condition
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* // Simple: User needs 'admin' OR 'manager'
|
|
51
|
-
* @RequirePermissionCondition({
|
|
52
|
-
* operator: 'or',
|
|
53
|
-
* permissions: ['admin', 'manager'],
|
|
54
|
-
* })
|
|
55
|
-
*
|
|
12
|
+
* Require complex permission logic using ILogicNode tree
|
|
56
13
|
* @example
|
|
57
|
-
* //
|
|
58
|
-
* @
|
|
59
|
-
* operator: 'and',
|
|
60
|
-
* permissions: ['users.read'],
|
|
61
|
-
* children: [
|
|
62
|
-
* { operator: 'or', permissions: ['admin', 'manager'] }
|
|
63
|
-
* ]
|
|
64
|
-
* })
|
|
65
|
-
*
|
|
14
|
+
* // Single permission
|
|
15
|
+
* @RequirePermissionLogic('users.read')
|
|
66
16
|
* @example
|
|
67
|
-
* //
|
|
68
|
-
* @
|
|
69
|
-
* operator: '
|
|
70
|
-
*
|
|
71
|
-
* {
|
|
72
|
-
*
|
|
73
|
-
*
|
|
17
|
+
* // Complex: users.read AND (admin OR manager)
|
|
18
|
+
* @RequirePermissionLogic({
|
|
19
|
+
* type: 'group', operator: 'AND', children: [
|
|
20
|
+
* { type: 'action', actionId: 'users.read' },
|
|
21
|
+
* { type: 'group', operator: 'OR', children: [
|
|
22
|
+
* { type: 'action', actionId: 'admin' },
|
|
23
|
+
* { type: 'action', actionId: 'manager' },
|
|
24
|
+
* ]},
|
|
25
|
+
* ],
|
|
74
26
|
* })
|
|
75
|
-
*/ export const
|
|
27
|
+
*/ export const RequirePermissionLogic = (logic)=>SetMetadata(PERMISSIONS_KEY, logic);
|
|
28
|
+
/** @deprecated Use RequirePermissionLogic instead */ export const RequirePermissionCondition = RequirePermissionLogic;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export var NotificationType = /*#__PURE__*/ function(NotificationType) {
|
|
2
|
+
NotificationType["INFO"] = "info";
|
|
3
|
+
NotificationType["WARNING"] = "warning";
|
|
4
|
+
NotificationType["SUCCESS"] = "success";
|
|
5
|
+
NotificationType["ERROR"] = "error";
|
|
6
|
+
return NotificationType;
|
|
7
|
+
}({});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export var ParticipantStatus = /*#__PURE__*/ function(ParticipantStatus) {
|
|
2
|
+
ParticipantStatus["PENDING"] = "pending";
|
|
3
|
+
ParticipantStatus["ACCEPTED"] = "accepted";
|
|
4
|
+
ParticipantStatus["DECLINED"] = "declined";
|
|
5
|
+
ParticipantStatus["TENTATIVE"] = "tentative";
|
|
6
|
+
return ParticipantStatus;
|
|
7
|
+
}({});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export var RecurrenceType = /*#__PURE__*/ function(RecurrenceType) {
|
|
2
|
+
RecurrenceType["NONE"] = "none";
|
|
3
|
+
RecurrenceType["DAILY"] = "daily";
|
|
4
|
+
RecurrenceType["WEEKLY"] = "weekly";
|
|
5
|
+
RecurrenceType["BIWEEKLY"] = "biweekly";
|
|
6
|
+
RecurrenceType["MONTHLY"] = "monthly";
|
|
7
|
+
return RecurrenceType;
|
|
8
|
+
}({});
|
|
@@ -13,8 +13,8 @@ import { ForbiddenException, InternalServerErrorException } from '@nestjs/common
|
|
|
13
13
|
/**
|
|
14
14
|
* Exception thrown when user lacks required permissions
|
|
15
15
|
*/ export class InsufficientPermissionsException extends ForbiddenException {
|
|
16
|
-
constructor(missingPermissions, operator = '
|
|
17
|
-
const message = operator === '
|
|
16
|
+
constructor(missingPermissions, operator = 'AND'){
|
|
17
|
+
const message = operator === 'OR' ? `Requires at least one of: ${missingPermissions.join(', ')}` : `Missing required permissions: ${missingPermissions.join(', ')}`;
|
|
18
18
|
super({
|
|
19
19
|
success: false,
|
|
20
20
|
message,
|
|
@@ -45,8 +45,6 @@ export class PermissionGuard {
|
|
|
45
45
|
context.getClass()
|
|
46
46
|
]);
|
|
47
47
|
if (!permissionConfig) return true;
|
|
48
|
-
const { permissions: requiredPermissions, operator } = this.normalizePermissionConfig(permissionConfig);
|
|
49
|
-
if (!requiredPermissions || requiredPermissions.length === 0) return true;
|
|
50
48
|
const request = context.switchToHttp().getRequest();
|
|
51
49
|
const user = request.user;
|
|
52
50
|
if (!user) throw new UnauthorizedException('Authentication required');
|
|
@@ -59,90 +57,93 @@ export class PermissionGuard {
|
|
|
59
57
|
this.logger.warn(`No permissions found (userId: ${user.id})`, 'PermissionGuard');
|
|
60
58
|
throw new NoPermissionsFoundException();
|
|
61
59
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} else {
|
|
69
|
-
this.validateSimplePermissions(requiredPermissions, userPermissions, operator);
|
|
60
|
+
const logicNode = this.normalizeToLogicNode(permissionConfig);
|
|
61
|
+
if (!logicNode) return true;
|
|
62
|
+
const result = this.evaluateLogicNode(logicNode, userPermissions);
|
|
63
|
+
if (!result.passed) {
|
|
64
|
+
this.logger.warn(`Permission denied (userId: ${user.id})`, 'PermissionGuard');
|
|
65
|
+
throw new InsufficientPermissionsException(result.missingPermissions, result.operator);
|
|
70
66
|
}
|
|
71
67
|
return true;
|
|
72
68
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
operator: config.operator || 'and'
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
validateSimplePermissions(requiredPermissions, userPermissions, operator) {
|
|
84
|
-
if (operator === 'or') {
|
|
85
|
-
const hasAny = requiredPermissions.some((p)=>this.hasPermission(userPermissions, p));
|
|
86
|
-
if (!hasAny) throw new InsufficientPermissionsException(requiredPermissions, 'or');
|
|
87
|
-
} else {
|
|
88
|
-
const hasAll = requiredPermissions.every((p)=>this.hasPermission(userPermissions, p));
|
|
89
|
-
if (!hasAll) {
|
|
90
|
-
const missing = requiredPermissions.filter((p)=>!this.hasPermission(userPermissions, p));
|
|
91
|
-
throw new InsufficientPermissionsException(missing, 'and');
|
|
92
|
-
}
|
|
69
|
+
normalizeToLogicNode(config) {
|
|
70
|
+
// string - single permission
|
|
71
|
+
if (typeof config === 'string') {
|
|
72
|
+
return config ? {
|
|
73
|
+
type: 'action',
|
|
74
|
+
actionId: config
|
|
75
|
+
} : null;
|
|
93
76
|
}
|
|
77
|
+
// string[] - treat as AND of multiple permissions
|
|
78
|
+
if (Array.isArray(config)) {
|
|
79
|
+
if (config.length === 0) return null;
|
|
80
|
+
if (config.length === 1) return {
|
|
81
|
+
type: 'action',
|
|
82
|
+
actionId: config[0]
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
type: 'group',
|
|
86
|
+
operator: 'AND',
|
|
87
|
+
children: config.map((p)=>({
|
|
88
|
+
type: 'action',
|
|
89
|
+
actionId: p
|
|
90
|
+
}))
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// SimplePermissionConfig - { permissions: string[], operator: 'AND'|'OR' }
|
|
94
|
+
if ('permissions' in config && Array.isArray(config.permissions)) {
|
|
95
|
+
const simple = config;
|
|
96
|
+
if (simple.permissions.length === 0) return null;
|
|
97
|
+
if (simple.permissions.length === 1) return {
|
|
98
|
+
type: 'action',
|
|
99
|
+
actionId: simple.permissions[0]
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
type: 'group',
|
|
103
|
+
operator: simple.operator || 'AND',
|
|
104
|
+
children: simple.permissions.map((p)=>({
|
|
105
|
+
type: 'action',
|
|
106
|
+
actionId: p
|
|
107
|
+
}))
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// ILogicNode
|
|
111
|
+
return config;
|
|
94
112
|
}
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
evaluateLogicNode(node, userPermissions) {
|
|
114
|
+
if (node.type === 'action') {
|
|
115
|
+
const passed = this.hasPermission(userPermissions, node.actionId);
|
|
116
|
+
return {
|
|
117
|
+
passed,
|
|
118
|
+
missingPermissions: passed ? [] : [
|
|
119
|
+
node.actionId
|
|
120
|
+
],
|
|
121
|
+
operator: 'AND'
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Group node
|
|
125
|
+
const { operator, children } = node;
|
|
126
|
+
// SECURITY: Fail-closed - deny access when no children configured
|
|
127
|
+
if (!children || children.length === 0) {
|
|
103
128
|
return {
|
|
104
129
|
passed: false,
|
|
105
|
-
message: 'No permissions configured - access denied by default',
|
|
106
130
|
missingPermissions: [],
|
|
107
131
|
operator
|
|
108
132
|
};
|
|
109
133
|
}
|
|
110
134
|
const results = [];
|
|
111
|
-
const failureDetails = [];
|
|
112
135
|
const missingPermissions = [];
|
|
113
|
-
if (permissions.length > 0) {
|
|
114
|
-
if (operator === 'or') {
|
|
115
|
-
const hasAny = permissions.some((p)=>this.hasPermission(userPermissions, p));
|
|
116
|
-
results.push(hasAny);
|
|
117
|
-
if (!hasAny) {
|
|
118
|
-
failureDetails.push(`needs one of: [${permissions.join(', ')}]`);
|
|
119
|
-
missingPermissions.push(...permissions);
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
const hasAll = permissions.every((p)=>this.hasPermission(userPermissions, p));
|
|
123
|
-
results.push(hasAll);
|
|
124
|
-
if (!hasAll) {
|
|
125
|
-
const missing = permissions.filter((p)=>!this.hasPermission(userPermissions, p));
|
|
126
|
-
failureDetails.push(`missing: [${missing.join(', ')}]`);
|
|
127
|
-
missingPermissions.push(...missing);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
136
|
for (const child of children){
|
|
132
|
-
const childResult = this.
|
|
137
|
+
const childResult = this.evaluateLogicNode(child, userPermissions);
|
|
133
138
|
results.push(childResult.passed);
|
|
134
139
|
if (!childResult.passed) {
|
|
135
|
-
failureDetails.push(`(${childResult.message})`);
|
|
136
140
|
missingPermissions.push(...childResult.missingPermissions);
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
|
-
|
|
140
|
-
const passed = operator === 'or' ? results.some((r)=>r) : results.every((r)=>r);
|
|
141
|
-
const message = passed ? 'OK' : `Denied: ${failureDetails.join(` ${operator.toUpperCase()} `)}`;
|
|
143
|
+
const passed = operator === 'OR' ? results.some((r)=>r) : results.every((r)=>r);
|
|
142
144
|
return {
|
|
143
145
|
passed,
|
|
144
|
-
|
|
145
|
-
missingPermissions,
|
|
146
|
+
missingPermissions: passed ? [] : missingPermissions,
|
|
146
147
|
operator
|
|
147
148
|
};
|
|
148
149
|
}
|
package/fesm/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const EVENT_MANAGER_ADAPTER = 'EVENT_MANAGER_ADAPTER';
|
package/fesm/interfaces/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './api.interface';
|
|
2
2
|
export * from './datasource.interface';
|
|
3
|
+
export * from './event-manager-adapter.interface';
|
|
3
4
|
export * from './identity.interface';
|
|
4
5
|
export * from './logged-user-info.interface';
|
|
5
6
|
export * from './logger.interface';
|
|
6
7
|
export * from './module-config.interface';
|
|
8
|
+
export * from './notification-adapter.interface';
|
|
7
9
|
export * from './permission.interface';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NOTIFICATION_ADAPTER = 'NOTIFICATION_ADAPTER';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { envConfig } from '@flusys/nestjs-core/config';
|
|
1
2
|
import { CLIENT_TYPE_HEADER } from '../constants';
|
|
2
3
|
/** Time unit multipliers in milliseconds */ const TIME_UNIT_MS = {
|
|
3
4
|
s: 1000,
|
|
@@ -30,7 +31,7 @@ import { CLIENT_TYPE_HEADER } from '../constants';
|
|
|
30
31
|
*/ export function buildCookieOptions(req) {
|
|
31
32
|
const hostname = req.hostname || '';
|
|
32
33
|
const origin = req.headers.origin || '';
|
|
33
|
-
const isProduction =
|
|
34
|
+
const isProduction = envConfig.isProduction();
|
|
34
35
|
const forwardedProto = req.headers['x-forwarded-proto'];
|
|
35
36
|
const isHttps = isProduction || forwardedProto === 'https' || origin.startsWith('https://') || req.secure;
|
|
36
37
|
let domain;
|
|
@@ -10,10 +10,8 @@ export declare class PermissionGuard implements CanActivate {
|
|
|
10
10
|
private readonly logger;
|
|
11
11
|
constructor(reflector: Reflector, cache?: HybridCache, config?: PermissionGuardConfig, logger?: ILogger);
|
|
12
12
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
13
|
-
private
|
|
14
|
-
private
|
|
15
|
-
private isNestedCondition;
|
|
16
|
-
private evaluateCondition;
|
|
13
|
+
private normalizeToLogicNode;
|
|
14
|
+
private evaluateLogicNode;
|
|
17
15
|
private getUserPermissions;
|
|
18
16
|
private buildPermissionCacheKey;
|
|
19
17
|
private hasPermission;
|
package/index.d.ts
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ParticipantStatus } from '../enums/participant-status.enum';
|
|
2
|
+
import { RecurrenceType } from '../enums/recurrence-type.enum';
|
|
3
|
+
export interface IEventManagerAdapter {
|
|
4
|
+
createEvent(options: CreateEventOptions): Promise<EventResult>;
|
|
5
|
+
addParticipants(eventId: string, userIds: string[], companyId?: string): Promise<void>;
|
|
6
|
+
removeParticipant(eventId: string, userId: string): Promise<void>;
|
|
7
|
+
updateParticipantStatus(participantId: string, status: ParticipantStatus): Promise<void>;
|
|
8
|
+
getEventsForUser?(userId: string, startDate: Date, endDate: Date, companyId?: string): Promise<EventResult[]>;
|
|
9
|
+
getEventById?(eventId: string): Promise<EventResult | null>;
|
|
10
|
+
}
|
|
11
|
+
export interface CreateEventOptions {
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
meetingLink?: string;
|
|
15
|
+
startDateTime: Date;
|
|
16
|
+
endDateTime: Date;
|
|
17
|
+
isAllDay?: boolean;
|
|
18
|
+
recurrenceType?: RecurrenceType;
|
|
19
|
+
recurrenceEndDate?: Date;
|
|
20
|
+
color?: string;
|
|
21
|
+
metadata?: Record<string, unknown>;
|
|
22
|
+
participantIds?: string[];
|
|
23
|
+
organizerId?: string;
|
|
24
|
+
companyId?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface EventResult {
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
description?: string | null;
|
|
30
|
+
meetingLink?: string | null;
|
|
31
|
+
startDateTime: Date;
|
|
32
|
+
endDateTime: Date;
|
|
33
|
+
isAllDay: boolean;
|
|
34
|
+
recurrenceType: string;
|
|
35
|
+
recurrenceEndDate?: Date | null;
|
|
36
|
+
color: string;
|
|
37
|
+
isActive: boolean;
|
|
38
|
+
metadata?: Record<string, unknown> | null;
|
|
39
|
+
companyId?: string | null;
|
|
40
|
+
createdAt: Date;
|
|
41
|
+
updatedAt: Date;
|
|
42
|
+
}
|
|
43
|
+
export declare const EVENT_MANAGER_ADAPTER = "EVENT_MANAGER_ADAPTER";
|
package/interfaces/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './api.interface';
|
|
2
2
|
export * from './datasource.interface';
|
|
3
|
+
export * from './event-manager-adapter.interface';
|
|
3
4
|
export * from './identity.interface';
|
|
4
5
|
export * from './logged-user-info.interface';
|
|
5
6
|
export * from './logger.interface';
|
|
6
7
|
export * from './module-config.interface';
|
|
8
|
+
export * from './notification-adapter.interface';
|
|
7
9
|
export * from './permission.interface';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { NotificationType } from '../enums/notification-type.enum';
|
|
2
|
+
export interface INotificationAdapter {
|
|
3
|
+
send(options: NotificationSendOptions): Promise<void>;
|
|
4
|
+
sendToMany(options: NotificationBulkSendOptions): Promise<void>;
|
|
5
|
+
broadcastToCompany?(companyId: string, title: string, message?: string, type?: NotificationType, data?: Record<string, unknown>): Promise<void>;
|
|
6
|
+
isUserOnline?(userId: string): boolean;
|
|
7
|
+
}
|
|
8
|
+
interface NotificationBaseOptions {
|
|
9
|
+
title: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
type?: NotificationType;
|
|
12
|
+
data?: Record<string, unknown>;
|
|
13
|
+
companyId?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface NotificationSendOptions extends NotificationBaseOptions {
|
|
16
|
+
userId: string;
|
|
17
|
+
}
|
|
18
|
+
export interface NotificationBulkSendOptions extends NotificationBaseOptions {
|
|
19
|
+
userIds: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare const NOTIFICATION_ADAPTER = "NOTIFICATION_ADAPTER";
|
|
22
|
+
export {};
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
operator: PermissionOperator;
|
|
5
|
-
children?: PermissionCondition[];
|
|
1
|
+
export interface IActionNode {
|
|
2
|
+
type: 'action';
|
|
3
|
+
actionId: string;
|
|
6
4
|
}
|
|
7
|
-
export interface
|
|
5
|
+
export interface IGroupNode {
|
|
6
|
+
type: 'group';
|
|
7
|
+
operator: 'AND' | 'OR';
|
|
8
|
+
children: ILogicNode[];
|
|
9
|
+
}
|
|
10
|
+
export type ILogicNode = IActionNode | IGroupNode;
|
|
11
|
+
export type IPermissionLogic = string | ILogicNode;
|
|
12
|
+
export interface SimplePermissionConfig {
|
|
8
13
|
permissions: string[];
|
|
9
|
-
operator:
|
|
14
|
+
operator: 'AND' | 'OR';
|
|
10
15
|
}
|
|
11
|
-
export type PermissionConfig =
|
|
16
|
+
export type PermissionConfig = IPermissionLogic | SimplePermissionConfig | string[];
|
|
12
17
|
export interface PermissionGuardConfig {
|
|
13
18
|
enableCompanyFeature?: boolean;
|
|
14
19
|
userPermissionKeyFormat?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-shared",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Common shared utilities for Flusys NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -46,6 +46,11 @@
|
|
|
46
46
|
"import": "./fesm/entities/index.js",
|
|
47
47
|
"require": "./cjs/entities/index.js"
|
|
48
48
|
},
|
|
49
|
+
"./enums": {
|
|
50
|
+
"types": "./enums/index.d.ts",
|
|
51
|
+
"import": "./fesm/enums/index.js",
|
|
52
|
+
"require": "./cjs/enums/index.js"
|
|
53
|
+
},
|
|
49
54
|
"./exceptions": {
|
|
50
55
|
"types": "./exceptions/index.d.ts",
|
|
51
56
|
"import": "./fesm/exceptions/index.js",
|
|
@@ -105,6 +110,6 @@
|
|
|
105
110
|
"winston-daily-rotate-file": "^5.0.0"
|
|
106
111
|
},
|
|
107
112
|
"dependencies": {
|
|
108
|
-
"@flusys/nestjs-core": "3.0.
|
|
113
|
+
"@flusys/nestjs-core": "3.0.1"
|
|
109
114
|
}
|
|
110
115
|
}
|