@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.
Files changed (189) hide show
  1. package/Models/DatabaseModels/Index.ts +11 -0
  2. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +43 -0
  3. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +662 -0
  4. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +584 -0
  5. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +546 -0
  6. package/Models/DatabaseModels/UserOnCallShiftReminder.ts +231 -0
  7. package/Models/DatabaseModels/UserOnCallShiftReminderLog.ts +331 -0
  8. package/Server/API/OnCallCalendarAPI.ts +2194 -0
  9. package/Server/EnvironmentConfig.ts +138 -0
  10. package/Server/Infrastructure/OnCallCalendarFeedCache.ts +1050 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.ts +253 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  13. package/Server/Middleware/OnCallCalendarFeedRateLimit.ts +487 -0
  14. package/Server/Services/Index.ts +12 -0
  15. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +32 -0
  16. package/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.ts +260 -0
  17. package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +70 -3
  18. package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +138 -3
  19. package/Server/Services/OnCallDutyPolicyScheduleService.ts +1465 -134
  20. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +167 -31
  21. package/Server/Services/ProjectOnCallCalendarFeedService.ts +192 -0
  22. package/Server/Services/TeamMemberService.ts +489 -1
  23. package/Server/Services/TeamService.ts +50 -0
  24. package/Server/Services/UserNotificationSettingService.ts +44 -1
  25. package/Server/Services/UserOnCallCalendarFeedService.ts +159 -0
  26. package/Server/Services/UserOnCallShiftReminderLogService.ts +151 -0
  27. package/Server/Services/UserOnCallShiftReminderService.ts +112 -0
  28. package/Server/Utils/OnCall/CalendarFeedToken.ts +241 -0
  29. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1488 -0
  30. package/Server/Utils/OnCall/OnCallCalendarFeedUrls.ts +230 -0
  31. package/Server/Utils/OnCall/OnCallShiftChangeListeners.ts +227 -0
  32. package/Server/Utils/OnCall/OnCallShiftMaterializer.ts +1127 -0
  33. package/Server/Utils/OnCall/OnCallShiftReminderListener.ts +174 -0
  34. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +2584 -0
  35. package/Server/Utils/Response.ts +134 -0
  36. package/Server/Utils/StartServer.ts +10 -0
  37. package/Server/Utils/Telemetry/AppMetrics.ts +51 -0
  38. package/Tests/App/Dashboard/OnCallCalendarFeedLinks.test.tsx +229 -0
  39. package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +489 -0
  40. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +149 -0
  41. package/Tests/App/Dashboard/OnCallCalendarFeedUtil.test.ts +855 -0
  42. package/Tests/App/Dashboard/OnCallPersonalCalendarFeed.test.tsx +1209 -0
  43. package/Tests/App/Dashboard/OnCallSharedCalendarFeedCard.test.tsx +1019 -0
  44. package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +655 -0
  45. package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +73 -0
  46. package/Tests/Models/OnCallCalendarFeedModels.test.ts +642 -0
  47. package/Tests/Models/OnCallDutyPolicyScheduleCalendarFeed.test.ts +288 -0
  48. package/Tests/Models/OnCallDutyPolicyScheduleShiftConfigVersion.test.ts +88 -0
  49. package/Tests/Models/UserOnCallShiftReminderModels.test.ts +368 -0
  50. package/Tests/Server/API/Helpers.ts +8 -0
  51. package/Tests/Server/API/OnCallCalendarAPI.test.ts +4461 -0
  52. package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +357 -0
  53. package/Tests/Server/Infrastructure/OnCallCalendarFeedCache.test.ts +1589 -0
  54. package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +369 -0
  55. package/Tests/Server/Middleware/OnCallCalendarFeedRateLimit.test.ts +1365 -0
  56. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +70 -0
  57. package/Tests/Server/Services/OnCallCalendarFeedServices.test.ts +1103 -0
  58. package/Tests/Server/Services/OnCallDutyPolicyScheduleResolver.test.ts +1037 -0
  59. package/Tests/Server/Services/OnCallShiftConfigPropagation.test.ts +1270 -0
  60. package/Tests/Server/Services/TeamDeleteMemberCleanup.test.ts +156 -0
  61. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +755 -0
  62. package/Tests/Server/Services/UserNotificationSettingShiftReminderDefaults.test.ts +267 -0
  63. package/Tests/Server/Services/UserOnCallShiftReminderServices.test.ts +583 -0
  64. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +254 -0
  65. package/Tests/Server/Utils/OnCall/CalendarFeedToken.test.ts +467 -0
  66. package/Tests/Server/Utils/OnCall/OnCallCalendarFeedRenderer.test.ts +2142 -0
  67. package/Tests/Server/Utils/OnCall/OnCallCalendarFeedUrls.test.ts +278 -0
  68. package/Tests/Server/Utils/OnCall/OnCallResolverTestHarness.ts +440 -0
  69. package/Tests/Server/Utils/OnCall/OnCallShiftChangeListeners.test.ts +314 -0
  70. package/Tests/Server/Utils/OnCall/OnCallShiftMaterializer.test.ts +1502 -0
  71. package/Tests/Server/Utils/OnCall/OnCallShiftReminderListener.test.ts +491 -0
  72. package/Tests/Server/Utils/OnCall/OnCallShiftReminderRunner.test.ts +3088 -0
  73. package/Tests/Server/Utils/OnCall/OnCallShiftReminderTestHarness.ts +910 -0
  74. package/Tests/Server/Utils/ResponseSendCalendarResponse.test.ts +561 -0
  75. package/Tests/Server/Utils/StartServerEncryptionSecretWarning.test.ts +64 -0
  76. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +29 -0
  77. package/Tests/Types/Calendar/ICalendar.test.ts +488 -0
  78. package/Tests/Types/NotificationSetting/NotificationSettingEventType.test.ts +53 -0
  79. package/Tests/Types/OnCallDutyPolicy/CalendarFeedTestFixtures.ts +310 -0
  80. package/Tests/Types/OnCallDutyPolicy/CalendarFeedWindow.test.ts +205 -0
  81. package/Tests/Types/OnCallDutyPolicy/LayerUtilLayerMetaAndIterationCap.test.ts +458 -0
  82. package/Tests/Types/OnCallDutyPolicy/MaterializedShift.test.ts +197 -0
  83. package/Tests/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.test.ts +1986 -0
  84. package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtilGroupKey.test.ts +678 -0
  85. package/Tests/Types/OnCallDutyPolicy/ShiftSeamUtil.test.ts +417 -0
  86. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  87. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  88. package/Types/Calendar/ICalendar.ts +442 -0
  89. package/Types/Email/EmailTemplateType.ts +2 -0
  90. package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
  91. package/Types/OnCallDutyPolicy/CalendarFeedWindow.ts +140 -0
  92. package/Types/OnCallDutyPolicy/Layer.ts +190 -35
  93. package/Types/OnCallDutyPolicy/MaterializedShift.ts +274 -0
  94. package/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.ts +1415 -0
  95. package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +159 -4
  96. package/Types/OnCallDutyPolicy/ShiftSeamUtil.ts +106 -0
  97. package/build/dist/Models/DatabaseModels/Index.js +11 -0
  98. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  99. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +44 -0
  100. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  101. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +699 -0
  102. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -0
  103. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +620 -0
  104. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -0
  105. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +585 -0
  106. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -0
  107. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js +247 -0
  108. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js.map +1 -0
  109. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js +355 -0
  110. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js.map +1 -0
  111. package/build/dist/Server/API/OnCallCalendarAPI.js +1371 -0
  112. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -0
  113. package/build/dist/Server/EnvironmentConfig.js +102 -0
  114. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  115. package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js +663 -0
  116. package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js.map +1 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js +103 -0
  118. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js.map +1 -0
  119. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  120. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  121. package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js +342 -0
  122. package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js.map +1 -0
  123. package/build/dist/Server/Services/Index.js +12 -0
  124. package/build/dist/Server/Services/Index.js.map +1 -1
  125. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +20 -0
  126. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  127. package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js +219 -0
  128. package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js.map +1 -0
  129. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +47 -3
  130. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
  131. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +112 -3
  132. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
  133. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +955 -9
  134. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  135. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +93 -6
  136. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  137. package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js +157 -0
  138. package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js.map +1 -0
  139. package/build/dist/Server/Services/TeamMemberService.js +396 -1
  140. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  141. package/build/dist/Server/Services/TeamService.js +43 -0
  142. package/build/dist/Server/Services/TeamService.js.map +1 -1
  143. package/build/dist/Server/Services/UserNotificationSettingService.js +26 -1
  144. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  145. package/build/dist/Server/Services/UserOnCallCalendarFeedService.js +140 -0
  146. package/build/dist/Server/Services/UserOnCallCalendarFeedService.js.map +1 -0
  147. package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js +116 -0
  148. package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js.map +1 -0
  149. package/build/dist/Server/Services/UserOnCallShiftReminderService.js +92 -0
  150. package/build/dist/Server/Services/UserOnCallShiftReminderService.js.map +1 -0
  151. package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js +161 -0
  152. package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js.map +1 -0
  153. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js +983 -0
  154. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js.map +1 -0
  155. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js +155 -0
  156. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js.map +1 -0
  157. package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js +145 -0
  158. package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js.map +1 -0
  159. package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js +752 -0
  160. package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js.map +1 -0
  161. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js +92 -0
  162. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js.map +1 -0
  163. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1786 -0
  164. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -0
  165. package/build/dist/Server/Utils/Response.js +97 -0
  166. package/build/dist/Server/Utils/Response.js.map +1 -1
  167. package/build/dist/Server/Utils/StartServer.js +9 -1
  168. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  169. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +41 -0
  170. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  171. package/build/dist/Types/Calendar/ICalendar.js +290 -0
  172. package/build/dist/Types/Calendar/ICalendar.js.map +1 -0
  173. package/build/dist/Types/Email/EmailTemplateType.js +2 -0
  174. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  175. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
  176. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
  177. package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js +97 -0
  178. package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js.map +1 -0
  179. package/build/dist/Types/OnCallDutyPolicy/Layer.js +113 -19
  180. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  181. package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js +134 -0
  182. package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js.map +1 -0
  183. package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js +800 -0
  184. package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js.map +1 -0
  185. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +97 -3
  186. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
  187. package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js +77 -0
  188. package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js.map +1 -0
  189. package/package.json +1 -1
@@ -0,0 +1,254 @@
1
+ import ModelPermission from "../../../../../Server/Types/Database/Permissions/Index";
2
+ import CalendarFeedToken from "../../../../../Server/Utils/OnCall/CalendarFeedToken";
3
+ import OnCallDutyPolicyScheduleCalendarFeed from "../../../../../Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed";
4
+ import ProjectOnCallCalendarFeed from "../../../../../Models/DatabaseModels/ProjectOnCallCalendarFeed";
5
+ import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
6
+ import NotAuthorizedException from "../../../../../Types/Exception/NotAuthorizedException";
7
+ import ObjectID from "../../../../../Types/ObjectID";
8
+ import Permission, {
9
+ UserTenantAccessPermission,
10
+ } from "../../../../../Types/Permission";
11
+ import { describe, expect, it } from "@jest/globals";
12
+
13
+ /*
14
+ * The permission gate on the SHARED calendar feeds, exercised for real.
15
+ *
16
+ * The shared schedule and project links are the one part of this feature that
17
+ * hands a project's whole on-call roster to anyone holding a URL, and the only
18
+ * thing standing between a project READER and rotating (or publishing) that
19
+ * link is ModelPermission. The API tests prove the routes make a non-root
20
+ * write with exactly `{ isEnabled }` as the probe, and the model tests prove
21
+ * the declared lists match OnCallDutyPolicySchedule's; what neither of them
22
+ * does is RUN the gate. These do: the declaration and the enforcement are
23
+ * checked against each other, so a change to either -- a widened column list,
24
+ * a tenant-wiring surprise, a probe that stops carrying a column -- is a red
25
+ * test rather than a reader who can rotate the team's link.
26
+ *
27
+ * The four "refused by the service" API tests next to these are mocked
28
+ * rejections: they prove the route propagates a 403, not that a 403 happens.
29
+ */
30
+
31
+ const projectId: ObjectID = ObjectID.generate();
32
+ const feedId: ObjectID = ObjectID.generate();
33
+ const scheduleId: ObjectID = ObjectID.generate();
34
+ const userId: ObjectID = ObjectID.generate();
35
+
36
+ function propsFor(
37
+ permissions: Array<Permission>,
38
+ ): DatabaseCommonInteractionProps {
39
+ const tenantPermission: UserTenantAccessPermission = {
40
+ projectId,
41
+ _type: "UserTenantAccessPermission",
42
+ permissions: permissions.map((permission: Permission) => {
43
+ return {
44
+ _type: "UserPermission",
45
+ permission: permission,
46
+ labelIds: [],
47
+ isBlockPermission: false,
48
+ };
49
+ }),
50
+ };
51
+
52
+ return {
53
+ userId,
54
+ tenantId: projectId,
55
+ userTenantAccessPermission: {
56
+ [projectId.toString()]: tenantPermission,
57
+ },
58
+ };
59
+ }
60
+
61
+ /* Exactly the probe write POST /schedule-feed/:id/rotate makes. */
62
+ async function probeScheduleFeedUpdate(
63
+ props: DatabaseCommonInteractionProps,
64
+ ): Promise<unknown> {
65
+ return await ModelPermission.checkUpdateQueryPermissions(
66
+ OnCallDutyPolicyScheduleCalendarFeed,
67
+ { _id: feedId.toString(), projectId: projectId },
68
+ { isEnabled: true },
69
+ props,
70
+ );
71
+ }
72
+
73
+ async function probeProjectFeedUpdate(
74
+ props: DatabaseCommonInteractionProps,
75
+ ): Promise<unknown> {
76
+ return await ModelPermission.checkUpdateQueryPermissions(
77
+ ProjectOnCallCalendarFeed,
78
+ { _id: feedId.toString(), projectId: projectId },
79
+ { isEnabled: true },
80
+ props,
81
+ );
82
+ }
83
+
84
+ /*
85
+ * What the service's onBeforeCreate leaves on createBy.data by the time
86
+ * DatabaseService runs the create check: the token columns are stamped by the
87
+ * SERVER and checked with the CALLER's permissions.
88
+ */
89
+ function stampedScheduleFeed(): OnCallDutyPolicyScheduleCalendarFeed {
90
+ const model: OnCallDutyPolicyScheduleCalendarFeed =
91
+ new OnCallDutyPolicyScheduleCalendarFeed();
92
+
93
+ model.projectId = projectId;
94
+ model.onCallDutyPolicyScheduleId = scheduleId;
95
+ CalendarFeedToken.applyTokenColumnsOnCreate(model, {
96
+ trustSuppliedToken: false,
97
+ });
98
+
99
+ return model;
100
+ }
101
+
102
+ function stampedProjectFeed(): ProjectOnCallCalendarFeed {
103
+ const model: ProjectOnCallCalendarFeed = new ProjectOnCallCalendarFeed();
104
+
105
+ model.projectId = projectId;
106
+ CalendarFeedToken.applyTokenColumnsOnCreate(model, {
107
+ trustSuppliedToken: false,
108
+ });
109
+
110
+ return model;
111
+ }
112
+
113
+ describe("shared calendar feeds: the real permission gate", () => {
114
+ describe("publishing and rotating needs edit rights on the schedule", () => {
115
+ for (const permission of [
116
+ Permission.Viewer,
117
+ Permission.OnCallViewer,
118
+ Permission.ReadProjectOnCallDutyPolicySchedule,
119
+ ]) {
120
+ it(`a ${permission} may not update the schedule feed`, async () => {
121
+ await expect(
122
+ probeScheduleFeedUpdate(propsFor([permission])),
123
+ ).rejects.toThrow(NotAuthorizedException);
124
+ });
125
+
126
+ it(`a ${permission} may not update the project feed`, async () => {
127
+ await expect(
128
+ probeProjectFeedUpdate(propsFor([permission])),
129
+ ).rejects.toThrow(NotAuthorizedException);
130
+ });
131
+
132
+ it(`a ${permission} may not create a schedule feed`, () => {
133
+ expect(() => {
134
+ ModelPermission.checkCreatePermissions(
135
+ OnCallDutyPolicyScheduleCalendarFeed,
136
+ stampedScheduleFeed(),
137
+ propsFor([permission]),
138
+ );
139
+ }).toThrow(NotAuthorizedException);
140
+ });
141
+
142
+ it(`a ${permission} may not create a project feed`, () => {
143
+ expect(() => {
144
+ ModelPermission.checkCreatePermissions(
145
+ ProjectOnCallCalendarFeed,
146
+ stampedProjectFeed(),
147
+ propsFor([permission]),
148
+ );
149
+ }).toThrow(NotAuthorizedException);
150
+ });
151
+ }
152
+
153
+ it("a caller with no permissions at all is refused (harness guard)", async () => {
154
+ await expect(probeScheduleFeedUpdate(propsFor([]))).rejects.toThrow(
155
+ NotAuthorizedException,
156
+ );
157
+ await expect(probeProjectFeedUpdate(propsFor([]))).rejects.toThrow(
158
+ NotAuthorizedException,
159
+ );
160
+ });
161
+ });
162
+
163
+ describe("an editor may publish and rotate", () => {
164
+ for (const permission of [
165
+ Permission.OnCallMember,
166
+ Permission.ProjectMember,
167
+ Permission.ProjectAdmin,
168
+ ]) {
169
+ it(`a ${permission} may update the schedule feed`, async () => {
170
+ await expect(
171
+ probeScheduleFeedUpdate(propsFor([permission])),
172
+ ).resolves.toBeDefined();
173
+ });
174
+
175
+ it(`a ${permission} may update the project feed`, async () => {
176
+ await expect(
177
+ probeProjectFeedUpdate(propsFor([permission])),
178
+ ).resolves.toBeDefined();
179
+ });
180
+ }
181
+
182
+ /*
183
+ * The create check runs on the STAMPED data, with the caller's
184
+ * permissions. The token columns are `computed`, which is what keeps a
185
+ * server-stamped secret from being refused for a caller who may not write
186
+ * it -- the same shape that once made the Slack/Teams feature dead on
187
+ * arrival (see WorkspaceMethodStampedColumnCreate.test.ts).
188
+ */
189
+ for (const permission of [
190
+ Permission.OnCallMember,
191
+ Permission.ProjectAdmin,
192
+ Permission.CreateProjectOnCallDutyPolicySchedule,
193
+ ]) {
194
+ it(`a ${permission} may create the schedule feed the service stamped`, () => {
195
+ expect(() => {
196
+ ModelPermission.checkCreatePermissions(
197
+ OnCallDutyPolicyScheduleCalendarFeed,
198
+ stampedScheduleFeed(),
199
+ propsFor([permission]),
200
+ );
201
+ }).not.toThrow();
202
+ });
203
+
204
+ it(`a ${permission} may create the project feed the service stamped`, () => {
205
+ expect(() => {
206
+ ModelPermission.checkCreatePermissions(
207
+ ProjectOnCallCalendarFeed,
208
+ stampedProjectFeed(),
209
+ propsFor([permission]),
210
+ );
211
+ }).not.toThrow();
212
+ });
213
+ }
214
+ });
215
+
216
+ /*
217
+ * "Any schedule reader may copy the link" is half the design, so it is
218
+ * pinned too: a reader must still be able to READ the row.
219
+ */
220
+ describe("any reader may copy the link", () => {
221
+ for (const permission of [Permission.Viewer, Permission.OnCallViewer]) {
222
+ it(`a ${permission} may read the schedule feed's non-secret columns`, async () => {
223
+ await expect(
224
+ ModelPermission.checkReadQueryPermission(
225
+ OnCallDutyPolicyScheduleCalendarFeed,
226
+ { projectId: projectId },
227
+ { _id: true, isEnabled: true, tokenHint: true },
228
+ propsFor([permission]),
229
+ ),
230
+ ).resolves.toBeDefined();
231
+ });
232
+ }
233
+
234
+ it("nobody, however privileged, may select the token columns", async () => {
235
+ await expect(
236
+ ModelPermission.checkReadQueryPermission(
237
+ OnCallDutyPolicyScheduleCalendarFeed,
238
+ { projectId: projectId },
239
+ { _id: true, token: true },
240
+ propsFor([Permission.ProjectOwner, Permission.ProjectAdmin]),
241
+ ),
242
+ ).rejects.toThrow();
243
+
244
+ await expect(
245
+ ModelPermission.checkReadQueryPermission(
246
+ ProjectOnCallCalendarFeed,
247
+ { projectId: projectId },
248
+ { _id: true, tokenHash: true },
249
+ propsFor([Permission.ProjectOwner, Permission.ProjectAdmin]),
250
+ ),
251
+ ).rejects.toThrow();
252
+ });
253
+ });
254
+ });