@escapenavigator/utils 2.0.33 → 2.0.34
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.
|
@@ -16,8 +16,37 @@ export type UserSessionPermissionTarget = {
|
|
|
16
16
|
authorId?: number | null;
|
|
17
17
|
date: string;
|
|
18
18
|
};
|
|
19
|
+
export type UserSessionClaimTarget = {
|
|
20
|
+
hold?: boolean;
|
|
21
|
+
userId?: number | null;
|
|
22
|
+
needReplace?: boolean;
|
|
23
|
+
start: string;
|
|
24
|
+
end: string;
|
|
25
|
+
locationId: number;
|
|
26
|
+
comment?: string | null;
|
|
27
|
+
};
|
|
28
|
+
export type UserSessionClaimDto = {
|
|
29
|
+
userId?: number | null;
|
|
30
|
+
needReplace?: boolean;
|
|
31
|
+
start?: string;
|
|
32
|
+
end?: string;
|
|
33
|
+
locationId?: number;
|
|
34
|
+
comment?: string | null;
|
|
35
|
+
hold?: boolean;
|
|
36
|
+
};
|
|
19
37
|
export declare const canEditOtherUserSessions: (role: UserSessionRolePermissions) => boolean;
|
|
20
38
|
export declare const isSessionDateTodayOrFuture: (date: string, today?: string) => boolean;
|
|
39
|
+
/** Unassigned shift or a shift with an open replace request — any employee may claim it. */
|
|
40
|
+
export declare const isOpenUserSession: (session: Pick<UserSessionClaimTarget, "userId" | "needReplace">) => boolean;
|
|
41
|
+
/**
|
|
42
|
+
* True when the actor is only claiming an open shift for themselves
|
|
43
|
+
* (assign userId / clear needReplace) without changing schedule fields.
|
|
44
|
+
*/
|
|
45
|
+
export declare const isTakingOpenUserSession: (params: {
|
|
46
|
+
session: UserSessionClaimTarget;
|
|
47
|
+
dto: UserSessionClaimDto;
|
|
48
|
+
actorId: number;
|
|
49
|
+
}) => boolean;
|
|
21
50
|
/** Returns an English denial message, or null when edit/delete is allowed. */
|
|
22
51
|
export declare const getUserSessionEditDenial: (params: {
|
|
23
52
|
session: UserSessionPermissionTarget;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.canEditUserSession = exports.getUserSessionCreateDenial = exports.getUserSessionEditDenial = exports.isSessionDateTodayOrFuture = exports.canEditOtherUserSessions = exports.USER_SESSION_ERRORS_EN = exports.USER_SESSION_ERROR_KEYS = void 0;
|
|
3
|
+
exports.canEditUserSession = exports.getUserSessionCreateDenial = exports.getUserSessionEditDenial = exports.isTakingOpenUserSession = exports.isOpenUserSession = exports.isSessionDateTodayOrFuture = exports.canEditOtherUserSessions = exports.USER_SESSION_ERRORS_EN = exports.USER_SESSION_ERROR_KEYS = void 0;
|
|
4
4
|
exports.USER_SESSION_ERROR_KEYS = {
|
|
5
5
|
shiftLocked: 'shiftLocked',
|
|
6
6
|
noPermission: 'noPermission',
|
|
@@ -23,6 +23,42 @@ const canEditOtherUserSessions = (role) => !!role.totalAccess || !!role.canEditW
|
|
|
23
23
|
exports.canEditOtherUserSessions = canEditOtherUserSessions;
|
|
24
24
|
const isSessionDateTodayOrFuture = (date, today = formatTodayYmd()) => today <= date;
|
|
25
25
|
exports.isSessionDateTodayOrFuture = isSessionDateTodayOrFuture;
|
|
26
|
+
/** Unassigned shift or a shift with an open replace request — any employee may claim it. */
|
|
27
|
+
const isOpenUserSession = (session) => session.userId == null || !!session.needReplace;
|
|
28
|
+
exports.isOpenUserSession = isOpenUserSession;
|
|
29
|
+
/**
|
|
30
|
+
* True when the actor is only claiming an open shift for themselves
|
|
31
|
+
* (assign userId / clear needReplace) without changing schedule fields.
|
|
32
|
+
*/
|
|
33
|
+
const isTakingOpenUserSession = (params) => {
|
|
34
|
+
const { session, dto, actorId } = params;
|
|
35
|
+
if (session.hold) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (!(0, exports.isOpenUserSession)(session)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (dto.userId !== actorId) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (dto.hold === true) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (dto.start != null && dto.start !== session.start) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (dto.end != null && dto.end !== session.end) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (dto.locationId != null && dto.locationId !== session.locationId) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (dto.comment != null && (dto.comment ?? '') !== (session.comment ?? '')) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
exports.isTakingOpenUserSession = isTakingOpenUserSession;
|
|
26
62
|
const formatTodayYmd = () => {
|
|
27
63
|
const d = new Date();
|
|
28
64
|
return `${d.getFullYear()}-${`${d.getMonth() + 1}`.padStart(2, '0')}-${`${d.getDate()}`.padStart(2, '0')}`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const user_session_permissions_1 = require("./user-session-permissions");
|
|
4
|
+
const openSession = {
|
|
5
|
+
hold: false,
|
|
6
|
+
userId: null,
|
|
7
|
+
needReplace: false,
|
|
8
|
+
start: '10:00',
|
|
9
|
+
end: '18:00',
|
|
10
|
+
locationId: 1,
|
|
11
|
+
comment: null,
|
|
12
|
+
};
|
|
13
|
+
describe('isOpenUserSession', () => {
|
|
14
|
+
it('is true when unassigned', () => {
|
|
15
|
+
expect((0, user_session_permissions_1.isOpenUserSession)({ userId: null, needReplace: false })).toBe(true);
|
|
16
|
+
expect((0, user_session_permissions_1.isOpenUserSession)({ userId: undefined, needReplace: false })).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it('is true when replace was requested', () => {
|
|
19
|
+
expect((0, user_session_permissions_1.isOpenUserSession)({ userId: 5, needReplace: true })).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('is false for a normal assigned shift', () => {
|
|
22
|
+
expect((0, user_session_permissions_1.isOpenUserSession)({ userId: 5, needReplace: false })).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('isTakingOpenUserSession', () => {
|
|
26
|
+
it('allows any employee to claim an unassigned shift for themselves', () => {
|
|
27
|
+
expect((0, user_session_permissions_1.isTakingOpenUserSession)({
|
|
28
|
+
session: openSession,
|
|
29
|
+
dto: {
|
|
30
|
+
userId: 42,
|
|
31
|
+
needReplace: false,
|
|
32
|
+
start: '10:00',
|
|
33
|
+
end: '18:00',
|
|
34
|
+
locationId: 1,
|
|
35
|
+
comment: null,
|
|
36
|
+
},
|
|
37
|
+
actorId: 42,
|
|
38
|
+
})).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it('allows claiming a shift with an open replace request', () => {
|
|
41
|
+
expect((0, user_session_permissions_1.isTakingOpenUserSession)({
|
|
42
|
+
session: { ...openSession, userId: 7, needReplace: true },
|
|
43
|
+
dto: {
|
|
44
|
+
userId: 42,
|
|
45
|
+
needReplace: false,
|
|
46
|
+
start: '10:00',
|
|
47
|
+
end: '18:00',
|
|
48
|
+
locationId: 1,
|
|
49
|
+
},
|
|
50
|
+
actorId: 42,
|
|
51
|
+
})).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
it('rejects claiming for another employee', () => {
|
|
54
|
+
expect((0, user_session_permissions_1.isTakingOpenUserSession)({
|
|
55
|
+
session: openSession,
|
|
56
|
+
dto: { userId: 99, start: '10:00', end: '18:00', locationId: 1 },
|
|
57
|
+
actorId: 42,
|
|
58
|
+
})).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
it('rejects locked shifts', () => {
|
|
61
|
+
expect((0, user_session_permissions_1.isTakingOpenUserSession)({
|
|
62
|
+
session: { ...openSession, hold: true },
|
|
63
|
+
dto: { userId: 42, start: '10:00', end: '18:00', locationId: 1 },
|
|
64
|
+
actorId: 42,
|
|
65
|
+
})).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
it('rejects when schedule fields change alongside the claim', () => {
|
|
68
|
+
expect((0, user_session_permissions_1.isTakingOpenUserSession)({
|
|
69
|
+
session: openSession,
|
|
70
|
+
dto: { userId: 42, start: '11:00', end: '18:00', locationId: 1 },
|
|
71
|
+
actorId: 42,
|
|
72
|
+
})).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
it('rejects already assigned shifts without replace request', () => {
|
|
75
|
+
expect((0, user_session_permissions_1.isTakingOpenUserSession)({
|
|
76
|
+
session: { ...openSession, userId: 7, needReplace: false },
|
|
77
|
+
dto: { userId: 42, start: '10:00', end: '18:00', locationId: 1 },
|
|
78
|
+
actorId: 42,
|
|
79
|
+
})).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('getUserSessionEditDenial', () => {
|
|
83
|
+
it('still requires author for non-manager edit of someone else\'s unassigned shift', () => {
|
|
84
|
+
expect((0, user_session_permissions_1.getUserSessionEditDenial)({
|
|
85
|
+
session: { hold: false, authorId: 1, date: '2099-01-01' },
|
|
86
|
+
role: {
|
|
87
|
+
totalAccess: false,
|
|
88
|
+
canEditWorkedHours: false,
|
|
89
|
+
canEditOwnWorkedHours: true,
|
|
90
|
+
},
|
|
91
|
+
userId: 42,
|
|
92
|
+
})).toBe(user_session_permissions_1.USER_SESSION_ERRORS_EN.notShiftAuthor);
|
|
93
|
+
});
|
|
94
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@escapenavigator/utils",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.34",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"test": "jest"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@escapenavigator/types": "^2.0.
|
|
17
|
+
"@escapenavigator/types": "^2.0.32",
|
|
18
18
|
"axios": "^0.21.4",
|
|
19
19
|
"class-transformer": "^0.5.1",
|
|
20
20
|
"class-validator": "^0.13.2",
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"ts-jest": "^29.1.1",
|
|
30
30
|
"typescript": "^5.6"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "e7c356a5eb4bdb5d606be29aa0e8571073d0c531"
|
|
33
33
|
}
|