@oneuptime/common 12.0.29 → 12.0.30
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/Models/DatabaseModels/Index.ts +11 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +43 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +662 -0
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +584 -0
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +546 -0
- package/Models/DatabaseModels/UserOnCallShiftReminder.ts +231 -0
- package/Models/DatabaseModels/UserOnCallShiftReminderLog.ts +331 -0
- package/Server/API/OnCallCalendarAPI.ts +2194 -0
- package/Server/EnvironmentConfig.ts +138 -0
- package/Server/Infrastructure/OnCallCalendarFeedCache.ts +1050 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.ts +253 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/OnCallCalendarFeedRateLimit.ts +487 -0
- package/Server/Services/Index.ts +12 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +32 -0
- package/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.ts +260 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +70 -3
- package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +138 -3
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +1465 -134
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +167 -31
- package/Server/Services/ProjectOnCallCalendarFeedService.ts +192 -0
- package/Server/Services/TeamMemberService.ts +489 -1
- package/Server/Services/TeamService.ts +50 -0
- package/Server/Services/UserNotificationSettingService.ts +44 -1
- package/Server/Services/UserOnCallCalendarFeedService.ts +159 -0
- package/Server/Services/UserOnCallShiftReminderLogService.ts +151 -0
- package/Server/Services/UserOnCallShiftReminderService.ts +112 -0
- package/Server/Utils/OnCall/CalendarFeedToken.ts +241 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1488 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedUrls.ts +230 -0
- package/Server/Utils/OnCall/OnCallShiftChangeListeners.ts +227 -0
- package/Server/Utils/OnCall/OnCallShiftMaterializer.ts +1127 -0
- package/Server/Utils/OnCall/OnCallShiftReminderListener.ts +174 -0
- package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +2584 -0
- package/Server/Utils/Response.ts +134 -0
- package/Server/Utils/StartServer.ts +10 -0
- package/Server/Utils/Telemetry/AppMetrics.ts +51 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedLinks.test.tsx +229 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +489 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +149 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedUtil.test.ts +855 -0
- package/Tests/App/Dashboard/OnCallPersonalCalendarFeed.test.tsx +1209 -0
- package/Tests/App/Dashboard/OnCallSharedCalendarFeedCard.test.tsx +1019 -0
- package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +655 -0
- package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +73 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +642 -0
- package/Tests/Models/OnCallDutyPolicyScheduleCalendarFeed.test.ts +288 -0
- package/Tests/Models/OnCallDutyPolicyScheduleShiftConfigVersion.test.ts +88 -0
- package/Tests/Models/UserOnCallShiftReminderModels.test.ts +368 -0
- package/Tests/Server/API/Helpers.ts +8 -0
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +4461 -0
- package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +357 -0
- package/Tests/Server/Infrastructure/OnCallCalendarFeedCache.test.ts +1589 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +369 -0
- package/Tests/Server/Middleware/OnCallCalendarFeedRateLimit.test.ts +1365 -0
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +70 -0
- package/Tests/Server/Services/OnCallCalendarFeedServices.test.ts +1103 -0
- package/Tests/Server/Services/OnCallDutyPolicyScheduleResolver.test.ts +1037 -0
- package/Tests/Server/Services/OnCallShiftConfigPropagation.test.ts +1270 -0
- package/Tests/Server/Services/TeamDeleteMemberCleanup.test.ts +156 -0
- package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +755 -0
- package/Tests/Server/Services/UserNotificationSettingShiftReminderDefaults.test.ts +267 -0
- package/Tests/Server/Services/UserOnCallShiftReminderServices.test.ts +583 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +254 -0
- package/Tests/Server/Utils/OnCall/CalendarFeedToken.test.ts +467 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedRenderer.test.ts +2142 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedUrls.test.ts +278 -0
- package/Tests/Server/Utils/OnCall/OnCallResolverTestHarness.ts +440 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftChangeListeners.test.ts +314 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftMaterializer.test.ts +1502 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderListener.test.ts +491 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderRunner.test.ts +3088 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderTestHarness.ts +910 -0
- package/Tests/Server/Utils/ResponseSendCalendarResponse.test.ts +561 -0
- package/Tests/Server/Utils/StartServerEncryptionSecretWarning.test.ts +64 -0
- package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +29 -0
- package/Tests/Types/Calendar/ICalendar.test.ts +488 -0
- package/Tests/Types/NotificationSetting/NotificationSettingEventType.test.ts +53 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedTestFixtures.ts +310 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedWindow.test.ts +205 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilLayerMetaAndIterationCap.test.ts +458 -0
- package/Tests/Types/OnCallDutyPolicy/MaterializedShift.test.ts +197 -0
- package/Tests/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.test.ts +1986 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtilGroupKey.test.ts +678 -0
- package/Tests/Types/OnCallDutyPolicy/ShiftSeamUtil.test.ts +417 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Types/Calendar/ICalendar.ts +442 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
- package/Types/OnCallDutyPolicy/CalendarFeedWindow.ts +140 -0
- package/Types/OnCallDutyPolicy/Layer.ts +190 -35
- package/Types/OnCallDutyPolicy/MaterializedShift.ts +274 -0
- package/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.ts +1415 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +159 -4
- package/Types/OnCallDutyPolicy/ShiftSeamUtil.ts +106 -0
- package/build/dist/Models/DatabaseModels/Index.js +11 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +44 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +699 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +620 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +585 -0
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js +247 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js +355 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js.map +1 -0
- package/build/dist/Server/API/OnCallCalendarAPI.js +1371 -0
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +102 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js +663 -0
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js +103 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js +342 -0
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js.map +1 -0
- package/build/dist/Server/Services/Index.js +12 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +20 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js +219 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +47 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +112 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +955 -9
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +93 -6
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js +157 -0
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/TeamMemberService.js +396 -1
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +43 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +26 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js +140 -0
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js +116 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js +92 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js +161 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js +983 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js +155 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js +145 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js +752 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js +92 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1786 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -0
- package/build/dist/Server/Utils/Response.js +97 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +9 -1
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +41 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Types/Calendar/ICalendar.js +290 -0
- package/build/dist/Types/Calendar/ICalendar.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +2 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js +97 -0
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +113 -19
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js +134 -0
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js +800 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +97 -3
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js +77 -0
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import AllModelTypes from "../../Models/DatabaseModels/Index";
|
|
2
|
+
import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
3
|
+
import OnCallDutyPolicySchedule from "../../Models/DatabaseModels/OnCallDutyPolicySchedule";
|
|
4
|
+
import OnCallDutyPolicyScheduleCalendarFeed from "../../Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed";
|
|
5
|
+
import ProjectOnCallCalendarFeed from "../../Models/DatabaseModels/ProjectOnCallCalendarFeed";
|
|
6
|
+
import { PlanType } from "../../Types/Billing/SubscriptionPlan";
|
|
7
|
+
import { ColumnAccessControl } from "../../Types/BaseDatabase/AccessControl";
|
|
8
|
+
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
9
|
+
import Permission from "../../Types/Permission";
|
|
10
|
+
import { describe, expect, test } from "@jest/globals";
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* The shared schedule feed is a project capability that renders one
|
|
14
|
+
* schedule's whole roster to whoever holds the link. Who may publish, rotate
|
|
15
|
+
* or copy it therefore has to be EXACTLY who may edit or read the schedule -
|
|
16
|
+
* not a hand-typed approximation that drifts the next time somebody adds a
|
|
17
|
+
* role tier to OnCallDutyPolicySchedule. This pins the four access lists to
|
|
18
|
+
* the schedule model's, operation by operation, and the same for the
|
|
19
|
+
* project-wide feed, which follows the schedule model rather than any of its
|
|
20
|
+
* own.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
type ModelType = { new (): BaseModel };
|
|
24
|
+
|
|
25
|
+
const schedule: OnCallDutyPolicySchedule = new OnCallDutyPolicySchedule();
|
|
26
|
+
const scheduleFeed: OnCallDutyPolicyScheduleCalendarFeed =
|
|
27
|
+
new OnCallDutyPolicyScheduleCalendarFeed();
|
|
28
|
+
const projectFeed: ProjectOnCallCalendarFeed = new ProjectOnCallCalendarFeed();
|
|
29
|
+
|
|
30
|
+
const SHARED_FEEDS: Array<[string, BaseModel]> = [
|
|
31
|
+
["OnCallDutyPolicyScheduleCalendarFeed", scheduleFeed],
|
|
32
|
+
["ProjectOnCallCalendarFeed", projectFeed],
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
describe("OnCallDutyPolicyScheduleCalendarFeed access control", () => {
|
|
36
|
+
test("the schedule model really carries four non-empty lists to copy", () => {
|
|
37
|
+
// Guards the equality assertions against passing on two empty lists.
|
|
38
|
+
expect(schedule.createRecordPermissions.length).toBeGreaterThan(0);
|
|
39
|
+
expect(schedule.readRecordPermissions.length).toBeGreaterThan(0);
|
|
40
|
+
expect(schedule.updateRecordPermissions.length).toBeGreaterThan(0);
|
|
41
|
+
expect(schedule.deleteRecordPermissions.length).toBeGreaterThan(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test.each(SHARED_FEEDS)(
|
|
45
|
+
"%s create list deep-equals the schedule's",
|
|
46
|
+
(_name: string, model: BaseModel) => {
|
|
47
|
+
expect(model.createRecordPermissions).toEqual(
|
|
48
|
+
schedule.createRecordPermissions,
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
test.each(SHARED_FEEDS)(
|
|
54
|
+
"%s read list deep-equals the schedule's",
|
|
55
|
+
(_name: string, model: BaseModel) => {
|
|
56
|
+
expect(model.readRecordPermissions).toEqual(
|
|
57
|
+
schedule.readRecordPermissions,
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
test.each(SHARED_FEEDS)(
|
|
63
|
+
"%s update list deep-equals the schedule's",
|
|
64
|
+
(_name: string, model: BaseModel) => {
|
|
65
|
+
expect(model.updateRecordPermissions).toEqual(
|
|
66
|
+
schedule.updateRecordPermissions,
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
test.each(SHARED_FEEDS)(
|
|
72
|
+
"%s delete list deep-equals the schedule's",
|
|
73
|
+
(_name: string, model: BaseModel) => {
|
|
74
|
+
expect(model.deleteRecordPermissions).toEqual(
|
|
75
|
+
schedule.deleteRecordPermissions,
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
test("the copied lists are the verbatim ones from the schedule model, in order", () => {
|
|
81
|
+
/*
|
|
82
|
+
* Written out so a reviewer can see the contract without opening the
|
|
83
|
+
* schedule model: editors publish/rotate, readers (incl. the viewer
|
|
84
|
+
* tiers) copy the link. If OnCallDutyPolicySchedule gains a tier this
|
|
85
|
+
* fails alongside the deep-equal tests above and tells you what changed.
|
|
86
|
+
*/
|
|
87
|
+
expect(scheduleFeed.createRecordPermissions).toEqual([
|
|
88
|
+
Permission.ProjectOwner,
|
|
89
|
+
Permission.ProjectAdmin,
|
|
90
|
+
Permission.ProjectMember,
|
|
91
|
+
Permission.OnCallAdmin,
|
|
92
|
+
Permission.OnCallMember,
|
|
93
|
+
Permission.CreateProjectOnCallDutyPolicySchedule,
|
|
94
|
+
]);
|
|
95
|
+
expect(scheduleFeed.readRecordPermissions).toEqual([
|
|
96
|
+
Permission.ProjectOwner,
|
|
97
|
+
Permission.ProjectAdmin,
|
|
98
|
+
Permission.ProjectMember,
|
|
99
|
+
Permission.Viewer,
|
|
100
|
+
Permission.OnCallAdmin,
|
|
101
|
+
Permission.OnCallMember,
|
|
102
|
+
Permission.OnCallViewer,
|
|
103
|
+
Permission.ReadProjectOnCallDutyPolicySchedule,
|
|
104
|
+
]);
|
|
105
|
+
expect(scheduleFeed.deleteRecordPermissions).toEqual([
|
|
106
|
+
Permission.ProjectOwner,
|
|
107
|
+
Permission.ProjectAdmin,
|
|
108
|
+
Permission.ProjectMember,
|
|
109
|
+
Permission.OnCallAdmin,
|
|
110
|
+
Permission.OnCallMember,
|
|
111
|
+
Permission.DeleteProjectOnCallDutyPolicySchedule,
|
|
112
|
+
]);
|
|
113
|
+
expect(scheduleFeed.updateRecordPermissions).toEqual([
|
|
114
|
+
Permission.ProjectOwner,
|
|
115
|
+
Permission.ProjectAdmin,
|
|
116
|
+
Permission.ProjectMember,
|
|
117
|
+
Permission.OnCallAdmin,
|
|
118
|
+
Permission.OnCallMember,
|
|
119
|
+
Permission.EditProjectOnCallDutyPolicySchedule,
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("no feed list names a permission the schedule does not (no new Permission members)", () => {
|
|
124
|
+
const schedulePermissions: Set<Permission> = new Set<Permission>([
|
|
125
|
+
...schedule.createRecordPermissions,
|
|
126
|
+
...schedule.readRecordPermissions,
|
|
127
|
+
...schedule.updateRecordPermissions,
|
|
128
|
+
...schedule.deleteRecordPermissions,
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
for (const [, model] of SHARED_FEEDS) {
|
|
132
|
+
for (const column of model.getTableColumns().columns) {
|
|
133
|
+
const accessControl: ColumnAccessControl | null =
|
|
134
|
+
model.getColumnAccessControlFor(column);
|
|
135
|
+
|
|
136
|
+
for (const permission of [
|
|
137
|
+
...(accessControl?.create || []),
|
|
138
|
+
...(accessControl?.read || []),
|
|
139
|
+
...(accessControl?.update || []),
|
|
140
|
+
]) {
|
|
141
|
+
expect(schedulePermissions.has(permission)).toBe(true);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("every readable column is readable by the whole schedule read list", () => {
|
|
148
|
+
/*
|
|
149
|
+
* A column readable by ProjectMember but not by OnCallViewer would turn a
|
|
150
|
+
* viewer's list request into a permission error on that field - the
|
|
151
|
+
* failure mode DomainRoleTierCoverage.test.ts exists for. Here it is
|
|
152
|
+
* pinned against the schedule's exact list, not just the tier trio.
|
|
153
|
+
*/
|
|
154
|
+
for (const [name, model] of SHARED_FEEDS) {
|
|
155
|
+
for (const column of model.getTableColumns().columns) {
|
|
156
|
+
const accessControl: ColumnAccessControl | null =
|
|
157
|
+
model.getColumnAccessControlFor(column);
|
|
158
|
+
|
|
159
|
+
if (!accessControl || accessControl.read.length === 0) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
expect({ model: name, column, read: accessControl.read }).toEqual({
|
|
164
|
+
model: name,
|
|
165
|
+
column,
|
|
166
|
+
read: schedule.readRecordPermissions,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("every creatable or updatable column uses the schedule's create/update lists", () => {
|
|
173
|
+
for (const [name, model] of SHARED_FEEDS) {
|
|
174
|
+
for (const column of model.getTableColumns().columns) {
|
|
175
|
+
const accessControl: ColumnAccessControl | null =
|
|
176
|
+
model.getColumnAccessControlFor(column);
|
|
177
|
+
|
|
178
|
+
if (!accessControl) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (accessControl.create.length > 0) {
|
|
183
|
+
expect({ model: name, column, create: accessControl.create }).toEqual(
|
|
184
|
+
{
|
|
185
|
+
model: name,
|
|
186
|
+
column,
|
|
187
|
+
create: schedule.createRecordPermissions,
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (accessControl.update.length > 0) {
|
|
193
|
+
expect({ model: name, column, update: accessControl.update }).toEqual(
|
|
194
|
+
{
|
|
195
|
+
model: name,
|
|
196
|
+
column,
|
|
197
|
+
update: schedule.updateRecordPermissions,
|
|
198
|
+
},
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe("OnCallDutyPolicyScheduleCalendarFeed shape", () => {
|
|
207
|
+
test("is registered in the model index", () => {
|
|
208
|
+
expect(
|
|
209
|
+
(AllModelTypes as Array<ModelType>).includes(
|
|
210
|
+
OnCallDutyPolicyScheduleCalendarFeed,
|
|
211
|
+
),
|
|
212
|
+
).toBe(true);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("is tenant scoped by projectId", () => {
|
|
216
|
+
expect(scheduleFeed.getTenantColumn()).toBe("projectId");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("follows the schedule's label scoping through the schedule relation", () => {
|
|
220
|
+
expect(scheduleFeed.canAccessIfCanReadOn).toBe("onCallDutyPolicySchedule");
|
|
221
|
+
|
|
222
|
+
// The relation the scoping follows must exist and point at the schedule.
|
|
223
|
+
expect(
|
|
224
|
+
scheduleFeed.getTableColumnMetadata("onCallDutyPolicySchedule").type,
|
|
225
|
+
).toBe(TableColumnType.Entity);
|
|
226
|
+
expect(
|
|
227
|
+
scheduleFeed.getTableColumnMetadata("onCallDutyPolicySchedule").modelType,
|
|
228
|
+
).toBe(OnCallDutyPolicySchedule);
|
|
229
|
+
expect(
|
|
230
|
+
scheduleFeed.getTableColumnMetadata("onCallDutyPolicySchedule")
|
|
231
|
+
.manyToOneRelationColumn,
|
|
232
|
+
).toBe("onCallDutyPolicyScheduleId");
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("the project feed has no single parent to scope by", () => {
|
|
236
|
+
expect(projectFeed.canAccessIfCanReadOn).toBeFalsy();
|
|
237
|
+
expect(projectFeed.getTableColumns().columns).not.toContain(
|
|
238
|
+
"onCallDutyPolicySchedule",
|
|
239
|
+
);
|
|
240
|
+
expect(projectFeed.getTableColumns().columns).not.toContain(
|
|
241
|
+
"onCallDutyPolicyScheduleId",
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("is served from its own CRUD route", () => {
|
|
246
|
+
expect(scheduleFeed.getCrudApiPath()?.toString()).toBe(
|
|
247
|
+
"/on-call-duty-policy-schedule-calendar-feed",
|
|
248
|
+
);
|
|
249
|
+
expect(projectFeed.getCrudApiPath()?.toString()).toBe(
|
|
250
|
+
"/project-on-call-calendar-feed",
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test.each(SHARED_FEEDS)(
|
|
255
|
+
"%s is plan gated like the schedule (Growth for every operation)",
|
|
256
|
+
(_name: string, model: BaseModel) => {
|
|
257
|
+
expect(model.getCreateBillingPlan()).toBe(PlanType.Growth);
|
|
258
|
+
expect(model.getReadBillingPlan()).toBe(PlanType.Growth);
|
|
259
|
+
expect(model.getUpdateBillingPlan()).toBe(PlanType.Growth);
|
|
260
|
+
expect(model.getDeleteBillingPlan()).toBe(PlanType.Growth);
|
|
261
|
+
|
|
262
|
+
expect(model.getCreateBillingPlan()).toBe(
|
|
263
|
+
schedule.getCreateBillingPlan(),
|
|
264
|
+
);
|
|
265
|
+
expect(model.getReadBillingPlan()).toBe(schedule.getReadBillingPlan());
|
|
266
|
+
expect(model.getUpdateBillingPlan()).toBe(
|
|
267
|
+
schedule.getUpdateBillingPlan(),
|
|
268
|
+
);
|
|
269
|
+
expect(model.getDeleteBillingPlan()).toBe(
|
|
270
|
+
schedule.getDeleteBillingPlan(),
|
|
271
|
+
);
|
|
272
|
+
},
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
test.each(SHARED_FEEDS)(
|
|
276
|
+
"%s stays reachable while a subscription is unpaid (links must not go dark)",
|
|
277
|
+
(_name: string, model: BaseModel) => {
|
|
278
|
+
expect(model.allowAccessIfSubscriptionIsUnpaid).toBe(true);
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
test.each(SHARED_FEEDS)(
|
|
283
|
+
"%s is not documented (no OpenAPI / Terraform surface for a secret-bearing table)",
|
|
284
|
+
(_name: string, model: BaseModel) => {
|
|
285
|
+
expect(model.enableDocumentation).toBeFalsy();
|
|
286
|
+
},
|
|
287
|
+
);
|
|
288
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import OnCallDutyPolicySchedule from "../../Models/DatabaseModels/OnCallDutyPolicySchedule";
|
|
2
|
+
import { ColumnAccessControl } from "../../Types/BaseDatabase/AccessControl";
|
|
3
|
+
import { TableColumnMetadata } from "../../Types/Database/TableColumn";
|
|
4
|
+
import TableColumnType from "../../Types/Database/TableColumnType";
|
|
5
|
+
import { describe, expect, test } from "@jest/globals";
|
|
6
|
+
import { getMetadataArgsStorage } from "typeorm";
|
|
7
|
+
import type { ColumnMetadataArgs } from "typeorm/metadata-args/ColumnMetadataArgs";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* shiftConfigVersion is the SEQUENCE of every calendar VEVENT and part of
|
|
11
|
+
* every feed cache key. Its contract is small and load-bearing: an integer
|
|
12
|
+
* that starts at 0, that readers of the schedule can see (the feed renderer
|
|
13
|
+
* reads it through the schedule relation), and that nobody can set through
|
|
14
|
+
* the API - it moves only by the service's atomic bump.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const schedule: OnCallDutyPolicySchedule = new OnCallDutyPolicySchedule();
|
|
18
|
+
|
|
19
|
+
function dbColumn(): ColumnMetadataArgs {
|
|
20
|
+
const column: ColumnMetadataArgs | undefined =
|
|
21
|
+
getMetadataArgsStorage().columns.find((entry: ColumnMetadataArgs) => {
|
|
22
|
+
return (
|
|
23
|
+
entry.target === OnCallDutyPolicySchedule &&
|
|
24
|
+
entry.propertyName === "shiftConfigVersion"
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (!column) {
|
|
29
|
+
throw new Error("OnCallDutyPolicySchedule.shiftConfigVersion is missing");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return column;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("OnCallDutyPolicySchedule.shiftConfigVersion", () => {
|
|
36
|
+
test("exists as a Number column", () => {
|
|
37
|
+
expect(schedule.getTableColumns().columns).toContain("shiftConfigVersion");
|
|
38
|
+
|
|
39
|
+
const metadata: TableColumnMetadata =
|
|
40
|
+
schedule.getTableColumnMetadata("shiftConfigVersion");
|
|
41
|
+
|
|
42
|
+
expect(metadata.type).toBe(TableColumnType.Number);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("starts at 0 - in the model metadata and at the database", () => {
|
|
46
|
+
const metadata: TableColumnMetadata =
|
|
47
|
+
schedule.getTableColumnMetadata("shiftConfigVersion");
|
|
48
|
+
|
|
49
|
+
expect(metadata.isDefaultValueColumn).toBe(true);
|
|
50
|
+
expect(metadata.defaultValue).toBe(0);
|
|
51
|
+
|
|
52
|
+
expect(dbColumn().options.default).toBe(0);
|
|
53
|
+
expect(dbColumn().options.nullable).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("is readable by everyone who may read the schedule, incl. through a relation", () => {
|
|
57
|
+
const accessControl: ColumnAccessControl | null =
|
|
58
|
+
schedule.getColumnAccessControlFor("shiftConfigVersion");
|
|
59
|
+
|
|
60
|
+
expect(accessControl?.read).toEqual(schedule.readRecordPermissions);
|
|
61
|
+
expect(accessControl?.read.length).toBeGreaterThan(0);
|
|
62
|
+
|
|
63
|
+
expect(
|
|
64
|
+
schedule.getTableColumnMetadata("shiftConfigVersion")
|
|
65
|
+
.canReadOnRelationQuery,
|
|
66
|
+
).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("cannot be set through the API on create or update", () => {
|
|
70
|
+
const accessControl: ColumnAccessControl | null =
|
|
71
|
+
schedule.getColumnAccessControlFor("shiftConfigVersion");
|
|
72
|
+
|
|
73
|
+
expect(accessControl?.create).toEqual([]);
|
|
74
|
+
expect(accessControl?.update).toEqual([]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("does not block a schedule create that omits it (required + default)", () => {
|
|
78
|
+
/*
|
|
79
|
+
* DatabaseService.checkRequiredFields skips a required column that is a
|
|
80
|
+
* default-value column, so `required: true` here documents intent
|
|
81
|
+
* without forcing every creator to send a 0.
|
|
82
|
+
*/
|
|
83
|
+
expect(schedule.getTableColumnMetadata("shiftConfigVersion").required).toBe(
|
|
84
|
+
true,
|
|
85
|
+
);
|
|
86
|
+
expect(schedule.isDefaultValueColumn("shiftConfigVersion")).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
});
|