@juki-team/commons 0.1.45 → 0.1.46
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/cjs/index.cjs +110 -9
- package/dist/esm/index.js +103 -9
- package/dist/types/constants/websocket.d.ts +14 -5
- package/dist/types/dto/socket.d.ts +37 -3
- package/dist/types/helpers/socket.d.ts +12 -1
- package/dist/types/types/socket.d.ts +22 -2
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -594,6 +594,8 @@ exports.WebSocketSubscriptionEvent = void 0;
|
|
|
594
594
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_CONTEST_CHANGES"] = "UNSUBSCRIBE_CONTEST_CHANGES";
|
|
595
595
|
WebSocketSubscriptionEvent["SUBSCRIBE_USER_NOTIFICATION"] = "SUBSCRIBE_USER_NOTIFICATION";
|
|
596
596
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_USER_NOTIFICATION"] = "UNSUBSCRIBE_USER_NOTIFICATION";
|
|
597
|
+
WebSocketSubscriptionEvent["SUBSCRIBE_SUBMISSIONS_JUDGING"] = "SUBSCRIBE_SUBMISSIONS_JUDGING";
|
|
598
|
+
WebSocketSubscriptionEvent["UNSUBSCRIBE_SUBMISSIONS_JUDGING"] = "UNSUBSCRIBE_SUBMISSIONS_JUDGING";
|
|
597
599
|
})(exports.WebSocketSubscriptionEvent || (exports.WebSocketSubscriptionEvent = {}));
|
|
598
600
|
exports.WebSocketResponseEvent = void 0;
|
|
599
601
|
(function (WebSocketResponseEvent) {
|
|
@@ -612,6 +614,7 @@ exports.WebSocketResponseEvent = void 0;
|
|
|
612
614
|
WebSocketResponseEvent["USER_NOTIFICATION_"] = "USER_NOTIFICATION_";
|
|
613
615
|
WebSocketResponseEvent["USER_NOTIFICATION_SUBMISSION"] = "USER_NOTIFICATION_SUBMISSION";
|
|
614
616
|
WebSocketResponseEvent["USER_NOTIFICATION_CONTEST_CLARIFICATION"] = "USER_NOTIFICATION_CONTEST_CLARIFICATION";
|
|
617
|
+
WebSocketResponseEvent["SUBMISSION_JUDGING"] = "SUBMISSION_JUDGING";
|
|
615
618
|
})(exports.WebSocketResponseEvent || (exports.WebSocketResponseEvent = {}));
|
|
616
619
|
/**
|
|
617
620
|
* Roles of a contest, with the same names as the contest members in the DB.
|
|
@@ -627,6 +630,25 @@ exports.ContestChannelRole = void 0;
|
|
|
627
630
|
ContestChannelRole["GUESTS"] = "guests";
|
|
628
631
|
ContestChannelRole["SPECTATORS"] = "spectators";
|
|
629
632
|
})(exports.ContestChannelRole || (exports.ContestChannelRole = {}));
|
|
633
|
+
/**
|
|
634
|
+
* Roles of a problem, the ones computed by `getProblemAccessPermissions` (backend).
|
|
635
|
+
* Each role has its own Ably channel: `problem:{problemKey}:{role}` (see `CHANNEL_PROBLEM`).
|
|
636
|
+
*/
|
|
637
|
+
exports.ProblemChannelRole = void 0;
|
|
638
|
+
(function (ProblemChannelRole) {
|
|
639
|
+
ProblemChannelRole["ADMINISTRATORS"] = "administrators";
|
|
640
|
+
ProblemChannelRole["MANAGERS"] = "managers";
|
|
641
|
+
ProblemChannelRole["SPECTATORS"] = "spectators";
|
|
642
|
+
})(exports.ProblemChannelRole || (exports.ProblemChannelRole = {}));
|
|
643
|
+
/**
|
|
644
|
+
* Roles of the public channels of a user: `user:{userId}:{role}` (see `CHANNEL_USER_ROLE`).
|
|
645
|
+
* There are no per-user permissions: `spectators` is everyone who can list the submissions of the user.
|
|
646
|
+
* The private channel of the user is `user:{userId}` (see `CHANNEL_USER`).
|
|
647
|
+
*/
|
|
648
|
+
exports.UserChannelRole = void 0;
|
|
649
|
+
(function (UserChannelRole) {
|
|
650
|
+
UserChannelRole["SPECTATORS"] = "spectators";
|
|
651
|
+
})(exports.UserChannelRole || (exports.UserChannelRole = {}));
|
|
630
652
|
|
|
631
653
|
exports.DataViewMode = void 0;
|
|
632
654
|
(function (DataViewMode) {
|
|
@@ -2234,12 +2256,14 @@ const EMPTY_USER_PERMISSIONS = {
|
|
|
2234
2256
|
const segment = (value) => encodeURIComponent(value);
|
|
2235
2257
|
/** private: events of one session (code runs, requested data) */
|
|
2236
2258
|
const CHANNEL_SESSION = (sessionId) => `session:${segment(sessionId)}`;
|
|
2237
|
-
/** private: events of one user (own submissions while the contest is frozen, notifications) */
|
|
2259
|
+
/** private: events of one user (own submissions while the contest is frozen, notifications, own problem crawls) */
|
|
2238
2260
|
const CHANNEL_USER = (userId) => `user:${segment(userId)}`;
|
|
2261
|
+
/** per role: public events of one user (judging of its submissions visible to everyone, see `UserChannelRole`) */
|
|
2262
|
+
const CHANNEL_USER_ROLE = (userId, role) => `user:${segment(userId)}:${role}`;
|
|
2239
2263
|
/** public: status of a submission when it is visible to everyone */
|
|
2240
2264
|
const CHANNEL_SUBMISSION = (submitId) => `submission:${segment(submitId)}`;
|
|
2241
|
-
/**
|
|
2242
|
-
const CHANNEL_PROBLEM = (problemKey) => `problem:${segment(problemKey)}`;
|
|
2265
|
+
/** per role: events of a problem for one role (judging of its submissions, see `ProblemChannelRole`) */
|
|
2266
|
+
const CHANNEL_PROBLEM = (problemKey, role) => `problem:${segment(problemKey)}:${role}`;
|
|
2243
2267
|
/** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
|
|
2244
2268
|
const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${role}`;
|
|
2245
2269
|
/**
|
|
@@ -2250,9 +2274,12 @@ const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${
|
|
|
2250
2274
|
* The identity of a member is its `clientId` (`sessionId|uiId`, verified by Ably), never its data.
|
|
2251
2275
|
*/
|
|
2252
2276
|
const CHANNEL_ORGANIZATION_PRESENCE = (organizationKey) => `presence:organization:${segment(organizationKey)}`;
|
|
2253
|
-
// capability resources (wildcards) of the public channels
|
|
2277
|
+
// capability resources (wildcards) of the public channels.
|
|
2278
|
+
// Ably: a trailing `*` replaces one or more segments, any other `*` exactly one segment. So `user:*:spectators`
|
|
2279
|
+
// matches every `user:{userId}:spectators` but never the private `user:{userId}`.
|
|
2280
|
+
// There is no public `problem:*`: it would also match the role channels `problem:{problemKey}:{role}`.
|
|
2254
2281
|
const CHANNEL_SUBMISSION_ALL = 'submission:*';
|
|
2255
|
-
const
|
|
2282
|
+
const CHANNEL_USER_SPECTATORS_ALL = `user:*:${exports.UserChannelRole.SPECTATORS}`;
|
|
2256
2283
|
/**
|
|
2257
2284
|
* Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
|
|
2258
2285
|
*/
|
|
@@ -2263,6 +2290,16 @@ const getContestChannelParams = (channel) => {
|
|
|
2263
2290
|
}
|
|
2264
2291
|
return { contestKey: decodeURIComponent(contestKey), role: role };
|
|
2265
2292
|
};
|
|
2293
|
+
/**
|
|
2294
|
+
* Returns the problem and role of a `CHANNEL_PROBLEM` channel name, or null if it is not one.
|
|
2295
|
+
*/
|
|
2296
|
+
const getProblemChannelParams = (channel) => {
|
|
2297
|
+
const [namespace, problemKey, role, ...rest] = channel.split(':');
|
|
2298
|
+
if (namespace !== 'problem' || !problemKey || rest.length || !Object.values(exports.ProblemChannelRole).includes(role)) {
|
|
2299
|
+
return null;
|
|
2300
|
+
}
|
|
2301
|
+
return { problemKey: decodeURIComponent(problemKey), role: role };
|
|
2302
|
+
};
|
|
2266
2303
|
|
|
2267
2304
|
const NEW_PAGE_SHEET = () => ({
|
|
2268
2305
|
id: uuid.v4(),
|
|
@@ -2974,6 +3011,23 @@ const isUnsubscribeUserNotificationWebSocketEventDto = (event) => {
|
|
|
2974
3011
|
return isWebsocketSubscription(event)
|
|
2975
3012
|
&& event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
|
|
2976
3013
|
};
|
|
3014
|
+
const isNonEmptyString = (value) => typeof value === 'string' && !!value;
|
|
3015
|
+
/**
|
|
3016
|
+
* Exactly one of `problemKey` / `contestKey` / `userId` is set.
|
|
3017
|
+
*/
|
|
3018
|
+
const isSubmissionsJudgingScope = (scope) => {
|
|
3019
|
+
return [scope?.problemKey, scope?.contestKey, scope?.userId].filter(isNonEmptyString).length === 1;
|
|
3020
|
+
};
|
|
3021
|
+
const isSubscribeSubmissionsJudgingWebSocketEventDto = (event) => {
|
|
3022
|
+
return isWebsocketSubscription(event)
|
|
3023
|
+
&& event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_JUDGING
|
|
3024
|
+
&& isSubmissionsJudgingScope(event);
|
|
3025
|
+
};
|
|
3026
|
+
const isUnsubscribeSubmissionsJudgingWebSocketEventDto = (event) => {
|
|
3027
|
+
return isWebsocketSubscription(event)
|
|
3028
|
+
&& event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_JUDGING
|
|
3029
|
+
&& isSubmissionsJudgingScope(event);
|
|
3030
|
+
};
|
|
2977
3031
|
// is WebSocketResponseEventDto, CHANNEL_SUBSCRIBE_CLIENT
|
|
2978
3032
|
const isWebSocketResponseEventDto = (event) => {
|
|
2979
3033
|
return Object.values(exports.WebSocketResponseEvent).includes(event?.event)
|
|
@@ -2995,6 +3049,18 @@ const isSubmissionRunStatusMessageWebSocketResponseEventDto = (event) => {
|
|
|
2995
3049
|
&& event?.verdict in exports.ProblemVerdict
|
|
2996
3050
|
&& typeof event?.points === 'number';
|
|
2997
3051
|
};
|
|
3052
|
+
const isSubmissionJudgingWebSocketResponseEventDto = (event) => {
|
|
3053
|
+
return isWebSocketResponseEventDto(event)
|
|
3054
|
+
&& event?.event === exports.WebSocketResponseEvent.SUBMISSION_JUDGING
|
|
3055
|
+
&& isNonEmptyString(event?.submitId)
|
|
3056
|
+
&& isNonEmptyString(event?.problemKey)
|
|
3057
|
+
&& (event?.contestKey === null || isNonEmptyString(event?.contestKey))
|
|
3058
|
+
&& isNonEmptyString(event?.userId)
|
|
3059
|
+
&& typeof event?.judging === 'boolean'
|
|
3060
|
+
&& event?.status in exports.SubmissionRunStatus
|
|
3061
|
+
&& event?.verdict in exports.ProblemVerdict
|
|
3062
|
+
&& typeof event?.points === 'number';
|
|
3063
|
+
};
|
|
2998
3064
|
const isUserMessageWebSocketResponseEventDto = (event) => {
|
|
2999
3065
|
return isWebSocketResponseEventDto(event)
|
|
3000
3066
|
&& event?.event === exports.WebSocketResponseEvent.USER_MESSAGE
|
|
@@ -3100,6 +3166,11 @@ const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
|
|
|
3100
3166
|
if (isUserNotificationWebSocketResponseEventDto(response)) {
|
|
3101
3167
|
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.USER_NOTIFICATION_, clientId, '*');
|
|
3102
3168
|
}
|
|
3169
|
+
if (isSubmissionJudgingWebSocketResponseEventDto(response)) {
|
|
3170
|
+
// one key for every table: the same event is published on several channels (problem / contest / user) and the
|
|
3171
|
+
// client deduplicates it, so it is dispatched once; each table filters by the submissions it lists
|
|
3172
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SUBMISSION_JUDGING, clientId, '*');
|
|
3173
|
+
}
|
|
3103
3174
|
return null;
|
|
3104
3175
|
};
|
|
3105
3176
|
/**
|
|
@@ -3111,12 +3182,23 @@ const getChannelOfWebSocketSubscribeEvent = (event) => {
|
|
|
3111
3182
|
if (isSubscribeSubmissionRunStatusWebSocketEventDto(event)) {
|
|
3112
3183
|
return CHANNEL_SUBMISSION(event.submitId);
|
|
3113
3184
|
}
|
|
3114
|
-
|
|
3115
|
-
return CHANNEL_PROBLEM(event.problemKey);
|
|
3116
|
-
}
|
|
3185
|
+
// SUBSCRIBE_PROBLEM_CRAWLED: the event arrives by the private user channel of who requested the crawl
|
|
3117
3186
|
if (isSubscribeContestChangesWebSocketEventDto(event) || isSubscribeSubmissionsCrawlWebSocketEventDto(event)) {
|
|
3118
3187
|
return CHANNEL_CONTEST(event.contestKey, exports.ContestChannelRole.SPECTATORS);
|
|
3119
3188
|
}
|
|
3189
|
+
if (isSubscribeSubmissionsJudgingWebSocketEventDto(event)) {
|
|
3190
|
+
// the judging start/end is published on the spectators channel when it is visible to everyone; the hidden ones
|
|
3191
|
+
// (frozen / quiet contests) arrive by the role channels of the contest (managers) and the private user channel
|
|
3192
|
+
if ('problemKey' in event && event.problemKey) {
|
|
3193
|
+
return CHANNEL_PROBLEM(event.problemKey, exports.ProblemChannelRole.SPECTATORS);
|
|
3194
|
+
}
|
|
3195
|
+
if ('contestKey' in event && event.contestKey) {
|
|
3196
|
+
return CHANNEL_CONTEST(event.contestKey, exports.ContestChannelRole.SPECTATORS);
|
|
3197
|
+
}
|
|
3198
|
+
if ('userId' in event && event.userId) {
|
|
3199
|
+
return CHANNEL_USER_ROLE(event.userId, exports.UserChannelRole.SPECTATORS);
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3120
3202
|
return null;
|
|
3121
3203
|
};
|
|
3122
3204
|
/**
|
|
@@ -3126,6 +3208,18 @@ const getContestKeyOfWebSocketSubscribeEvent = (event) => {
|
|
|
3126
3208
|
if (isSubscribeContestChangesWebSocketEventDto(event) || isSubscribeSubmissionsCrawlWebSocketEventDto(event)) {
|
|
3127
3209
|
return event.contestKey;
|
|
3128
3210
|
}
|
|
3211
|
+
if (isSubscribeSubmissionsJudgingWebSocketEventDto(event) && 'contestKey' in event && event.contestKey) {
|
|
3212
|
+
return event.contestKey;
|
|
3213
|
+
}
|
|
3214
|
+
return null;
|
|
3215
|
+
};
|
|
3216
|
+
/**
|
|
3217
|
+
* Problem whose role channels the client needs (the API grants them when the token is requested with this problem).
|
|
3218
|
+
*/
|
|
3219
|
+
const getProblemKeyOfWebSocketSubscribeEvent = (event) => {
|
|
3220
|
+
if (isSubscribeSubmissionsJudgingWebSocketEventDto(event) && 'problemKey' in event && event.problemKey) {
|
|
3221
|
+
return event.problemKey;
|
|
3222
|
+
}
|
|
3129
3223
|
return null;
|
|
3130
3224
|
};
|
|
3131
3225
|
|
|
@@ -3327,11 +3421,12 @@ exports.AssignmentType = AssignmentType;
|
|
|
3327
3421
|
exports.CHANNEL_CONTEST = CHANNEL_CONTEST;
|
|
3328
3422
|
exports.CHANNEL_ORGANIZATION_PRESENCE = CHANNEL_ORGANIZATION_PRESENCE;
|
|
3329
3423
|
exports.CHANNEL_PROBLEM = CHANNEL_PROBLEM;
|
|
3330
|
-
exports.CHANNEL_PROBLEM_ALL = CHANNEL_PROBLEM_ALL;
|
|
3331
3424
|
exports.CHANNEL_SESSION = CHANNEL_SESSION;
|
|
3332
3425
|
exports.CHANNEL_SUBMISSION = CHANNEL_SUBMISSION;
|
|
3333
3426
|
exports.CHANNEL_SUBMISSION_ALL = CHANNEL_SUBMISSION_ALL;
|
|
3334
3427
|
exports.CHANNEL_USER = CHANNEL_USER;
|
|
3428
|
+
exports.CHANNEL_USER_ROLE = CHANNEL_USER_ROLE;
|
|
3429
|
+
exports.CHANNEL_USER_SPECTATORS_ALL = CHANNEL_USER_SPECTATORS_ALL;
|
|
3335
3430
|
exports.CODE_LANGUAGE = CODE_LANGUAGE;
|
|
3336
3431
|
exports.CONTEST_ROLE = CONTEST_ROLE;
|
|
3337
3432
|
exports.CONTEST_STATUS = CONTEST_STATUS;
|
|
@@ -3470,8 +3565,10 @@ exports.getMonths = getMonths;
|
|
|
3470
3565
|
exports.getParamsOfClientId = getParamsOfClientId;
|
|
3471
3566
|
exports.getParamsOfUserKey = getParamsOfUserKey;
|
|
3472
3567
|
exports.getPlainText = getPlainText;
|
|
3568
|
+
exports.getProblemChannelParams = getProblemChannelParams;
|
|
3473
3569
|
exports.getProblemCommentKey = getProblemCommentKey;
|
|
3474
3570
|
exports.getProblemJudgeKey = getProblemJudgeKey;
|
|
3571
|
+
exports.getProblemKeyOfWebSocketSubscribeEvent = getProblemKeyOfWebSocketSubscribeEvent;
|
|
3475
3572
|
exports.getRandomString = getRandomString;
|
|
3476
3573
|
exports.getSeconds = getSeconds;
|
|
3477
3574
|
exports.getSummaryWorksheetsInPages = getSummaryWorksheetsInPages;
|
|
@@ -3532,14 +3629,17 @@ exports.isSendDataRunCommandWebSocketResponseEventDto = isSendDataRunCommandWebS
|
|
|
3532
3629
|
exports.isSendDataSsmSessionsListWebSocketResponseEventDto = isSendDataSsmSessionsListWebSocketResponseEventDto;
|
|
3533
3630
|
exports.isSendDataWebSocketResponseEventDto = isSendDataWebSocketResponseEventDto;
|
|
3534
3631
|
exports.isStringJson = isStringJson;
|
|
3632
|
+
exports.isSubmissionJudgingWebSocketResponseEventDto = isSubmissionJudgingWebSocketResponseEventDto;
|
|
3535
3633
|
exports.isSubmissionRunStatusMessageWebSocketResponseEventDto = isSubmissionRunStatusMessageWebSocketResponseEventDto;
|
|
3536
3634
|
exports.isSubmissionsCrawlWebSocketResponseEventDto = isSubmissionsCrawlWebSocketResponseEventDto;
|
|
3635
|
+
exports.isSubmissionsJudgingScope = isSubmissionsJudgingScope;
|
|
3537
3636
|
exports.isSubscribeCodeRunStatusWebSocketEventDto = isSubscribeCodeRunStatusWebSocketEventDto;
|
|
3538
3637
|
exports.isSubscribeContestChangesWebSocketEventDto = isSubscribeContestChangesWebSocketEventDto;
|
|
3539
3638
|
exports.isSubscribeGetDataWebSocketEventDto = isSubscribeGetDataWebSocketEventDto;
|
|
3540
3639
|
exports.isSubscribeProblemCrawledWebSocketEventDto = isSubscribeProblemCrawledWebSocketEventDto;
|
|
3541
3640
|
exports.isSubscribeSubmissionRunStatusWebSocketEventDto = isSubscribeSubmissionRunStatusWebSocketEventDto;
|
|
3542
3641
|
exports.isSubscribeSubmissionsCrawlWebSocketEventDto = isSubscribeSubmissionsCrawlWebSocketEventDto;
|
|
3642
|
+
exports.isSubscribeSubmissionsJudgingWebSocketEventDto = isSubscribeSubmissionsJudgingWebSocketEventDto;
|
|
3543
3643
|
exports.isSubscribeUserNotificationWebSocketEventDto = isSubscribeUserNotificationWebSocketEventDto;
|
|
3544
3644
|
exports.isTeamMember = isTeamMember;
|
|
3545
3645
|
exports.isToday = isToday;
|
|
@@ -3549,6 +3649,7 @@ exports.isUnsubscribeGetDataWebSocketEventDto = isUnsubscribeGetDataWebSocketEve
|
|
|
3549
3649
|
exports.isUnsubscribeProblemCrawledWebSocketEventDto = isUnsubscribeProblemCrawledWebSocketEventDto;
|
|
3550
3650
|
exports.isUnsubscribeSubmissionRunStatusWebSocketEventDto = isUnsubscribeSubmissionRunStatusWebSocketEventDto;
|
|
3551
3651
|
exports.isUnsubscribeSubmissionsCrawlWebSocketEventDto = isUnsubscribeSubmissionsCrawlWebSocketEventDto;
|
|
3652
|
+
exports.isUnsubscribeSubmissionsJudgingWebSocketEventDto = isUnsubscribeSubmissionsJudgingWebSocketEventDto;
|
|
3552
3653
|
exports.isUnsubscribeUserNotificationWebSocketEventDto = isUnsubscribeUserNotificationWebSocketEventDto;
|
|
3553
3654
|
exports.isUserMember = isUserMember;
|
|
3554
3655
|
exports.isUserMessageWebSocketResponseEventDto = isUserMessageWebSocketResponseEventDto;
|
package/dist/esm/index.js
CHANGED
|
@@ -592,6 +592,8 @@ var WebSocketSubscriptionEvent;
|
|
|
592
592
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_CONTEST_CHANGES"] = "UNSUBSCRIBE_CONTEST_CHANGES";
|
|
593
593
|
WebSocketSubscriptionEvent["SUBSCRIBE_USER_NOTIFICATION"] = "SUBSCRIBE_USER_NOTIFICATION";
|
|
594
594
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_USER_NOTIFICATION"] = "UNSUBSCRIBE_USER_NOTIFICATION";
|
|
595
|
+
WebSocketSubscriptionEvent["SUBSCRIBE_SUBMISSIONS_JUDGING"] = "SUBSCRIBE_SUBMISSIONS_JUDGING";
|
|
596
|
+
WebSocketSubscriptionEvent["UNSUBSCRIBE_SUBMISSIONS_JUDGING"] = "UNSUBSCRIBE_SUBMISSIONS_JUDGING";
|
|
595
597
|
})(WebSocketSubscriptionEvent || (WebSocketSubscriptionEvent = {}));
|
|
596
598
|
var WebSocketResponseEvent;
|
|
597
599
|
(function (WebSocketResponseEvent) {
|
|
@@ -610,6 +612,7 @@ var WebSocketResponseEvent;
|
|
|
610
612
|
WebSocketResponseEvent["USER_NOTIFICATION_"] = "USER_NOTIFICATION_";
|
|
611
613
|
WebSocketResponseEvent["USER_NOTIFICATION_SUBMISSION"] = "USER_NOTIFICATION_SUBMISSION";
|
|
612
614
|
WebSocketResponseEvent["USER_NOTIFICATION_CONTEST_CLARIFICATION"] = "USER_NOTIFICATION_CONTEST_CLARIFICATION";
|
|
615
|
+
WebSocketResponseEvent["SUBMISSION_JUDGING"] = "SUBMISSION_JUDGING";
|
|
613
616
|
})(WebSocketResponseEvent || (WebSocketResponseEvent = {}));
|
|
614
617
|
/**
|
|
615
618
|
* Roles of a contest, with the same names as the contest members in the DB.
|
|
@@ -625,6 +628,25 @@ var ContestChannelRole;
|
|
|
625
628
|
ContestChannelRole["GUESTS"] = "guests";
|
|
626
629
|
ContestChannelRole["SPECTATORS"] = "spectators";
|
|
627
630
|
})(ContestChannelRole || (ContestChannelRole = {}));
|
|
631
|
+
/**
|
|
632
|
+
* Roles of a problem, the ones computed by `getProblemAccessPermissions` (backend).
|
|
633
|
+
* Each role has its own Ably channel: `problem:{problemKey}:{role}` (see `CHANNEL_PROBLEM`).
|
|
634
|
+
*/
|
|
635
|
+
var ProblemChannelRole;
|
|
636
|
+
(function (ProblemChannelRole) {
|
|
637
|
+
ProblemChannelRole["ADMINISTRATORS"] = "administrators";
|
|
638
|
+
ProblemChannelRole["MANAGERS"] = "managers";
|
|
639
|
+
ProblemChannelRole["SPECTATORS"] = "spectators";
|
|
640
|
+
})(ProblemChannelRole || (ProblemChannelRole = {}));
|
|
641
|
+
/**
|
|
642
|
+
* Roles of the public channels of a user: `user:{userId}:{role}` (see `CHANNEL_USER_ROLE`).
|
|
643
|
+
* There are no per-user permissions: `spectators` is everyone who can list the submissions of the user.
|
|
644
|
+
* The private channel of the user is `user:{userId}` (see `CHANNEL_USER`).
|
|
645
|
+
*/
|
|
646
|
+
var UserChannelRole;
|
|
647
|
+
(function (UserChannelRole) {
|
|
648
|
+
UserChannelRole["SPECTATORS"] = "spectators";
|
|
649
|
+
})(UserChannelRole || (UserChannelRole = {}));
|
|
628
650
|
|
|
629
651
|
var DataViewMode;
|
|
630
652
|
(function (DataViewMode) {
|
|
@@ -2232,12 +2254,14 @@ const EMPTY_USER_PERMISSIONS = {
|
|
|
2232
2254
|
const segment = (value) => encodeURIComponent(value);
|
|
2233
2255
|
/** private: events of one session (code runs, requested data) */
|
|
2234
2256
|
const CHANNEL_SESSION = (sessionId) => `session:${segment(sessionId)}`;
|
|
2235
|
-
/** private: events of one user (own submissions while the contest is frozen, notifications) */
|
|
2257
|
+
/** private: events of one user (own submissions while the contest is frozen, notifications, own problem crawls) */
|
|
2236
2258
|
const CHANNEL_USER = (userId) => `user:${segment(userId)}`;
|
|
2259
|
+
/** per role: public events of one user (judging of its submissions visible to everyone, see `UserChannelRole`) */
|
|
2260
|
+
const CHANNEL_USER_ROLE = (userId, role) => `user:${segment(userId)}:${role}`;
|
|
2237
2261
|
/** public: status of a submission when it is visible to everyone */
|
|
2238
2262
|
const CHANNEL_SUBMISSION = (submitId) => `submission:${segment(submitId)}`;
|
|
2239
|
-
/**
|
|
2240
|
-
const CHANNEL_PROBLEM = (problemKey) => `problem:${segment(problemKey)}`;
|
|
2263
|
+
/** per role: events of a problem for one role (judging of its submissions, see `ProblemChannelRole`) */
|
|
2264
|
+
const CHANNEL_PROBLEM = (problemKey, role) => `problem:${segment(problemKey)}:${role}`;
|
|
2241
2265
|
/** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
|
|
2242
2266
|
const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${role}`;
|
|
2243
2267
|
/**
|
|
@@ -2248,9 +2272,12 @@ const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${
|
|
|
2248
2272
|
* The identity of a member is its `clientId` (`sessionId|uiId`, verified by Ably), never its data.
|
|
2249
2273
|
*/
|
|
2250
2274
|
const CHANNEL_ORGANIZATION_PRESENCE = (organizationKey) => `presence:organization:${segment(organizationKey)}`;
|
|
2251
|
-
// capability resources (wildcards) of the public channels
|
|
2275
|
+
// capability resources (wildcards) of the public channels.
|
|
2276
|
+
// Ably: a trailing `*` replaces one or more segments, any other `*` exactly one segment. So `user:*:spectators`
|
|
2277
|
+
// matches every `user:{userId}:spectators` but never the private `user:{userId}`.
|
|
2278
|
+
// There is no public `problem:*`: it would also match the role channels `problem:{problemKey}:{role}`.
|
|
2252
2279
|
const CHANNEL_SUBMISSION_ALL = 'submission:*';
|
|
2253
|
-
const
|
|
2280
|
+
const CHANNEL_USER_SPECTATORS_ALL = `user:*:${UserChannelRole.SPECTATORS}`;
|
|
2254
2281
|
/**
|
|
2255
2282
|
* Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
|
|
2256
2283
|
*/
|
|
@@ -2261,6 +2288,16 @@ const getContestChannelParams = (channel) => {
|
|
|
2261
2288
|
}
|
|
2262
2289
|
return { contestKey: decodeURIComponent(contestKey), role: role };
|
|
2263
2290
|
};
|
|
2291
|
+
/**
|
|
2292
|
+
* Returns the problem and role of a `CHANNEL_PROBLEM` channel name, or null if it is not one.
|
|
2293
|
+
*/
|
|
2294
|
+
const getProblemChannelParams = (channel) => {
|
|
2295
|
+
const [namespace, problemKey, role, ...rest] = channel.split(':');
|
|
2296
|
+
if (namespace !== 'problem' || !problemKey || rest.length || !Object.values(ProblemChannelRole).includes(role)) {
|
|
2297
|
+
return null;
|
|
2298
|
+
}
|
|
2299
|
+
return { problemKey: decodeURIComponent(problemKey), role: role };
|
|
2300
|
+
};
|
|
2264
2301
|
|
|
2265
2302
|
const NEW_PAGE_SHEET = () => ({
|
|
2266
2303
|
id: v4(),
|
|
@@ -2972,6 +3009,23 @@ const isUnsubscribeUserNotificationWebSocketEventDto = (event) => {
|
|
|
2972
3009
|
return isWebsocketSubscription(event)
|
|
2973
3010
|
&& event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
|
|
2974
3011
|
};
|
|
3012
|
+
const isNonEmptyString = (value) => typeof value === 'string' && !!value;
|
|
3013
|
+
/**
|
|
3014
|
+
* Exactly one of `problemKey` / `contestKey` / `userId` is set.
|
|
3015
|
+
*/
|
|
3016
|
+
const isSubmissionsJudgingScope = (scope) => {
|
|
3017
|
+
return [scope?.problemKey, scope?.contestKey, scope?.userId].filter(isNonEmptyString).length === 1;
|
|
3018
|
+
};
|
|
3019
|
+
const isSubscribeSubmissionsJudgingWebSocketEventDto = (event) => {
|
|
3020
|
+
return isWebsocketSubscription(event)
|
|
3021
|
+
&& event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_JUDGING
|
|
3022
|
+
&& isSubmissionsJudgingScope(event);
|
|
3023
|
+
};
|
|
3024
|
+
const isUnsubscribeSubmissionsJudgingWebSocketEventDto = (event) => {
|
|
3025
|
+
return isWebsocketSubscription(event)
|
|
3026
|
+
&& event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_JUDGING
|
|
3027
|
+
&& isSubmissionsJudgingScope(event);
|
|
3028
|
+
};
|
|
2975
3029
|
// is WebSocketResponseEventDto, CHANNEL_SUBSCRIBE_CLIENT
|
|
2976
3030
|
const isWebSocketResponseEventDto = (event) => {
|
|
2977
3031
|
return Object.values(WebSocketResponseEvent).includes(event?.event)
|
|
@@ -2993,6 +3047,18 @@ const isSubmissionRunStatusMessageWebSocketResponseEventDto = (event) => {
|
|
|
2993
3047
|
&& event?.verdict in ProblemVerdict
|
|
2994
3048
|
&& typeof event?.points === 'number';
|
|
2995
3049
|
};
|
|
3050
|
+
const isSubmissionJudgingWebSocketResponseEventDto = (event) => {
|
|
3051
|
+
return isWebSocketResponseEventDto(event)
|
|
3052
|
+
&& event?.event === WebSocketResponseEvent.SUBMISSION_JUDGING
|
|
3053
|
+
&& isNonEmptyString(event?.submitId)
|
|
3054
|
+
&& isNonEmptyString(event?.problemKey)
|
|
3055
|
+
&& (event?.contestKey === null || isNonEmptyString(event?.contestKey))
|
|
3056
|
+
&& isNonEmptyString(event?.userId)
|
|
3057
|
+
&& typeof event?.judging === 'boolean'
|
|
3058
|
+
&& event?.status in SubmissionRunStatus
|
|
3059
|
+
&& event?.verdict in ProblemVerdict
|
|
3060
|
+
&& typeof event?.points === 'number';
|
|
3061
|
+
};
|
|
2996
3062
|
const isUserMessageWebSocketResponseEventDto = (event) => {
|
|
2997
3063
|
return isWebSocketResponseEventDto(event)
|
|
2998
3064
|
&& event?.event === WebSocketResponseEvent.USER_MESSAGE
|
|
@@ -3098,6 +3164,11 @@ const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
|
|
|
3098
3164
|
if (isUserNotificationWebSocketResponseEventDto(response)) {
|
|
3099
3165
|
return getWebSocketResponseEventKey(WebSocketResponseEvent.USER_NOTIFICATION_, clientId, '*');
|
|
3100
3166
|
}
|
|
3167
|
+
if (isSubmissionJudgingWebSocketResponseEventDto(response)) {
|
|
3168
|
+
// one key for every table: the same event is published on several channels (problem / contest / user) and the
|
|
3169
|
+
// client deduplicates it, so it is dispatched once; each table filters by the submissions it lists
|
|
3170
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.SUBMISSION_JUDGING, clientId, '*');
|
|
3171
|
+
}
|
|
3101
3172
|
return null;
|
|
3102
3173
|
};
|
|
3103
3174
|
/**
|
|
@@ -3109,12 +3180,23 @@ const getChannelOfWebSocketSubscribeEvent = (event) => {
|
|
|
3109
3180
|
if (isSubscribeSubmissionRunStatusWebSocketEventDto(event)) {
|
|
3110
3181
|
return CHANNEL_SUBMISSION(event.submitId);
|
|
3111
3182
|
}
|
|
3112
|
-
|
|
3113
|
-
return CHANNEL_PROBLEM(event.problemKey);
|
|
3114
|
-
}
|
|
3183
|
+
// SUBSCRIBE_PROBLEM_CRAWLED: the event arrives by the private user channel of who requested the crawl
|
|
3115
3184
|
if (isSubscribeContestChangesWebSocketEventDto(event) || isSubscribeSubmissionsCrawlWebSocketEventDto(event)) {
|
|
3116
3185
|
return CHANNEL_CONTEST(event.contestKey, ContestChannelRole.SPECTATORS);
|
|
3117
3186
|
}
|
|
3187
|
+
if (isSubscribeSubmissionsJudgingWebSocketEventDto(event)) {
|
|
3188
|
+
// the judging start/end is published on the spectators channel when it is visible to everyone; the hidden ones
|
|
3189
|
+
// (frozen / quiet contests) arrive by the role channels of the contest (managers) and the private user channel
|
|
3190
|
+
if ('problemKey' in event && event.problemKey) {
|
|
3191
|
+
return CHANNEL_PROBLEM(event.problemKey, ProblemChannelRole.SPECTATORS);
|
|
3192
|
+
}
|
|
3193
|
+
if ('contestKey' in event && event.contestKey) {
|
|
3194
|
+
return CHANNEL_CONTEST(event.contestKey, ContestChannelRole.SPECTATORS);
|
|
3195
|
+
}
|
|
3196
|
+
if ('userId' in event && event.userId) {
|
|
3197
|
+
return CHANNEL_USER_ROLE(event.userId, UserChannelRole.SPECTATORS);
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3118
3200
|
return null;
|
|
3119
3201
|
};
|
|
3120
3202
|
/**
|
|
@@ -3124,6 +3206,18 @@ const getContestKeyOfWebSocketSubscribeEvent = (event) => {
|
|
|
3124
3206
|
if (isSubscribeContestChangesWebSocketEventDto(event) || isSubscribeSubmissionsCrawlWebSocketEventDto(event)) {
|
|
3125
3207
|
return event.contestKey;
|
|
3126
3208
|
}
|
|
3209
|
+
if (isSubscribeSubmissionsJudgingWebSocketEventDto(event) && 'contestKey' in event && event.contestKey) {
|
|
3210
|
+
return event.contestKey;
|
|
3211
|
+
}
|
|
3212
|
+
return null;
|
|
3213
|
+
};
|
|
3214
|
+
/**
|
|
3215
|
+
* Problem whose role channels the client needs (the API grants them when the token is requested with this problem).
|
|
3216
|
+
*/
|
|
3217
|
+
const getProblemKeyOfWebSocketSubscribeEvent = (event) => {
|
|
3218
|
+
if (isSubscribeSubmissionsJudgingWebSocketEventDto(event) && 'problemKey' in event && event.problemKey) {
|
|
3219
|
+
return event.problemKey;
|
|
3220
|
+
}
|
|
3127
3221
|
return null;
|
|
3128
3222
|
};
|
|
3129
3223
|
|
|
@@ -3318,4 +3412,4 @@ const isQuizTextSheet = (value) => {
|
|
|
3318
3412
|
&& ['text', 'number', 'textarea'].includes(value?.inputType);
|
|
3319
3413
|
};
|
|
3320
3414
|
|
|
3321
|
-
export { ACCEPTED_PROGRAMMING_LANGUAGES, ASPECT_RATIO, AspectRatio, AssignmentClass, AssignmentState, AssignmentType, CHANNEL_CONTEST, CHANNEL_ORGANIZATION_PRESENCE, CHANNEL_PROBLEM,
|
|
3415
|
+
export { ACCEPTED_PROGRAMMING_LANGUAGES, ASPECT_RATIO, AspectRatio, AssignmentClass, AssignmentState, AssignmentType, CHANNEL_CONTEST, CHANNEL_ORGANIZATION_PRESENCE, CHANNEL_PROBLEM, CHANNEL_SESSION, CHANNEL_SUBMISSION, CHANNEL_SUBMISSION_ALL, CHANNEL_USER, CHANNEL_USER_ROLE, CHANNEL_USER_SPECTATORS_ALL, CODE_LANGUAGE, CONTEST_ROLE, CONTEST_STATUS, COOKIE_JUKI_SESSION_ID, COURSE_ROLE, CodeLanguage, CollectionKey, ContestChannelRole, ContestEventAction, ContestProblemBlockedByType, ContestProblemPrerequisiteType, ContestStatus, ContestTimeStatus, CourseRole, CourseStatus, CourseType, DAY_NAMES, DEFAULT_JUKI_PROFILE_IMAGE, DataViewMode, EMPTY_DOCUMENT_MEMBERS, EMPTY_ENTITY_MEMBERS, EMPTY_USER_PERMISSIONS, ENTITY_ACCESS, ENTITY_STATE, ERROR, EmailSubscription, EmailValidationState, EntityAccess, EntityCollection, EntityMembersRank, EntityState, EntityStatus, ErrorCode, FILE_ROLE, FILE_TYPE, FileMemberRole, FileType, FilesJukiPub, GroupType, HEADER_JUKI_FORWARDED_HOST, HEADER_JUKI_INTERNAL_API_KEY, HEADER_JUKI_METADATA, HEADER_JUKI_SECRET_TOKEN, HEADER_JUKI_VISITOR_SESSION_ID, HOURS, HTTPMethod, JUDGE, JUKI_APP_EMAIL_TEMPLATE, JUKI_APP_ORGANIZATION_KEY, JkError, Judge, LANGUAGE, LOWERCASE_LETTERS, Language, LogLevel, LogOperation, MAX_DATE, MEMBER_ROLE, MILLISECONDS, MINUTES, MIN_DATE, MONTH_NAMES, MemberRole, MemberType, MenuViewMode, NEW_PAGE_SHEET, NUMBERS, NotificationType, ONE_DAY, ONE_HOUR, ONE_MINUTE, ONE_SECOND, ONE_WEEK, ORGANIZATION_PLAN, OrganizationLogoType, OrganizationPlan, PAGE, PAGE_SIZE, PAGE_SIZES, PALLETE, PROBLEM_INPUT, PROBLEM_MODE, PROBLEM_MODES, PROBLEM_OUTPUT, PROBLEM_ROLE, PROBLEM_TYPE, PROBLEM_TYPES, PROBLEM_VERDICT, PROBLEM_VERDICTS, ProblemChannelRole, ProblemInput, ProblemOutput, ProblemScoringMode, ProblemType, ProblemVerdict, ProfileSetting, QuizScoringMode, RUNNER_ACCEPTED_PROBLEM_MODES, RUNNER_ACCEPTED_PROBLEM_TYPES, RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES, RUNNER_TYPE, Role, RunnerType, SECONDS, SEC_120, SEC_30, SEC_60, SEC_90, SEPARATOR_TOKEN, SUBMISSION_RUN_STATUS, SUPPORT_EMAIL, SYSTEM_ROLE, ScopeData, Status, SubmissionRunStatus, SystemRole, TEAM_ROLE, THEME, TeamRole, TeamStatus, Theme, TypeTestCase, UPPERCASE_LETTERS, USER_ROLE, USER_STATUS, UserChannelRole, UserRole, UserStatus, UserTeamStatus, WebSocketResponseEvent, WebSocketSubscriptionEvent, WorkingIn, WorksheetType, YEARS, _KEY, _SUB_SUB_TAB, _SUB_TAB, _TAB, _TYPE, areArraysDifferent, changeDay, changeHours, changeMilliseconds, changeMinutes, changeMonth, changeSeconds, changeYear, chunkString, cleanRequest, clearAsyncInterval, consoleError, consoleInfo, consoleWarn, contentResponse, contentsResponse, decreaseDay, decreaseMonth, decreaseYear, endOfDay, endOfHour, endOfMinute, endOfMonth, endOfSecond, endOfWeek, endOfYear, errorsResponse, getAssignmentCommentKey, getAssignmentUserCommentKey, getChannelOfWebSocketSubscribeEvent, getClientId, getContestChannelParams, getContestCommentKey, getContestKeyOfWebSocketSubscribeEvent, getDataLog, getDataOfTestCase, getDays, getDefaultMeta, getDocumentAccess, getHours, getMilliseconds, getMinutes, getMonths, getParamsOfClientId, getParamsOfUserKey, getPlainText, getProblemChannelParams, getProblemCommentKey, getProblemJudgeKey, getProblemKeyOfWebSocketSubscribeEvent, getRandomString, getSeconds, getSummaryWorksheetsInPages, getTotalExercisesOfSummaryWorksheetsInPages, getUserKey, getVerdictFromTestCase, getWebSocketResponseEventKey, getWebSocketResponseEventKeyOfResponse, getWorksheetsInPages, getYears, humanFileSize, increaseDay, increaseMonth, increaseYear, indexToLetters, isAfter, isBasicWorksheet, isBefore, isCodeEditorSheet, isCodeRunStatusMessageWebSocketResponseEventDto, isContestAssignment, isContestChangesWebSocketResponseEventDto, isCourseAssignment, isDayAfter, isDayBefore, isEndlessContest, isEqual, isFutureContest, isGlobalContest, isHoursAfter, isHoursBefore, isJkmdSheet, isMillisecondsAfter, isMillisecondsBefore, isMinutesAfter, isMinutesBefore, isMonthAfter, isMonthBefore, isObjectJson, isPastContest, isProblemCrawledWebSocketResponseEventDto, isQuizOptionsSheet, isQuizProblemSheet, isQuizTextSheet, isSameDay, isSameHour, isSameMillisecond, isSameMinute, isSameMonth, isSameSecond, isSameYear, isSecondsAfter, isSecondsBefore, isSendDataEc2InstancesListWebSocketResponseEventDto, isSendDataEcsTaskDefinitionListWebSocketResponseEventDto, isSendDataEcsTasksListWebSocketResponseEventDto, isSendDataRunCommandWebSocketResponseEventDto, isSendDataSsmSessionsListWebSocketResponseEventDto, isSendDataWebSocketResponseEventDto, isStringJson, isSubmissionJudgingWebSocketResponseEventDto, isSubmissionRunStatusMessageWebSocketResponseEventDto, isSubmissionsCrawlWebSocketResponseEventDto, isSubmissionsJudgingScope, isSubscribeCodeRunStatusWebSocketEventDto, isSubscribeContestChangesWebSocketEventDto, isSubscribeGetDataWebSocketEventDto, isSubscribeProblemCrawledWebSocketEventDto, isSubscribeSubmissionRunStatusWebSocketEventDto, isSubscribeSubmissionsCrawlWebSocketEventDto, isSubscribeSubmissionsJudgingWebSocketEventDto, isSubscribeUserNotificationWebSocketEventDto, isTeamMember, isToday, isUnsubscribeCodeRunStatusWebSocketEventDto, isUnsubscribeContestChangesWebSocketEventDto, isUnsubscribeGetDataWebSocketEventDto, isUnsubscribeProblemCrawledWebSocketEventDto, isUnsubscribeSubmissionRunStatusWebSocketEventDto, isUnsubscribeSubmissionsCrawlWebSocketEventDto, isUnsubscribeSubmissionsJudgingWebSocketEventDto, isUnsubscribeUserNotificationWebSocketEventDto, isUserMember, isUserMessageWebSocketResponseEventDto, isUserNotificationContestClarificationWebSocketResponseEventDto, isUserNotificationSubmissionWebSocketResponseEventDto, isUserNotificationWebSocketResponseEventDto, isValidDate, isWebSocketChannelsMessageDto, isWebSocketResponseEventDto, isWebsocketSubscription, isWithinInterval, isWorksheetAssignment, isYearAfter, isYearBefore, join, lettersToIndex, memorySizeOf, mergeVerdicts, mex, normalizeToLocalStartOfDay, normalizeToLocalStartOfHour, normalizeToLocalStartOfMinutes, normalizeToLocalStartOfSeconds, objectUpdate, objectsUpdate, padEnd, padStart, range, removeExtension, safeJsonParse, setAsyncInterval, split, splitTime, startOfDay, startOfHour, startOfMinute, startOfMonth, startOfSecond, startOfWeek, startOfYear, stringToArrayBuffer, toEntityMembersDto, toJkError };
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { ContestChannelRole } from '../types';
|
|
1
|
+
import { ContestChannelRole, ProblemChannelRole, UserChannelRole } from '../types';
|
|
2
2
|
/** private: events of one session (code runs, requested data) */
|
|
3
3
|
export declare const CHANNEL_SESSION: (sessionId: string) => string;
|
|
4
|
-
/** private: events of one user (own submissions while the contest is frozen, notifications) */
|
|
4
|
+
/** private: events of one user (own submissions while the contest is frozen, notifications, own problem crawls) */
|
|
5
5
|
export declare const CHANNEL_USER: (userId: string) => string;
|
|
6
|
+
/** per role: public events of one user (judging of its submissions visible to everyone, see `UserChannelRole`) */
|
|
7
|
+
export declare const CHANNEL_USER_ROLE: (userId: string, role: UserChannelRole) => string;
|
|
6
8
|
/** public: status of a submission when it is visible to everyone */
|
|
7
9
|
export declare const CHANNEL_SUBMISSION: (submitId: string) => string;
|
|
8
|
-
/**
|
|
9
|
-
export declare const CHANNEL_PROBLEM: (problemKey: string) => string;
|
|
10
|
+
/** per role: events of a problem for one role (judging of its submissions, see `ProblemChannelRole`) */
|
|
11
|
+
export declare const CHANNEL_PROBLEM: (problemKey: string, role: ProblemChannelRole) => string;
|
|
10
12
|
/** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
|
|
11
13
|
export declare const CHANNEL_CONTEST: (contestKey: string, role: ContestChannelRole) => string;
|
|
12
14
|
/**
|
|
@@ -18,7 +20,7 @@ export declare const CHANNEL_CONTEST: (contestKey: string, role: ContestChannelR
|
|
|
18
20
|
*/
|
|
19
21
|
export declare const CHANNEL_ORGANIZATION_PRESENCE: (organizationKey: string) => string;
|
|
20
22
|
export declare const CHANNEL_SUBMISSION_ALL = "submission:*";
|
|
21
|
-
export declare const
|
|
23
|
+
export declare const CHANNEL_USER_SPECTATORS_ALL = "user:*:spectators";
|
|
22
24
|
/**
|
|
23
25
|
* Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
|
|
24
26
|
*/
|
|
@@ -26,3 +28,10 @@ export declare const getContestChannelParams: (channel: string) => {
|
|
|
26
28
|
contestKey: string;
|
|
27
29
|
role: ContestChannelRole;
|
|
28
30
|
} | null;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the problem and role of a `CHANNEL_PROBLEM` channel name, or null if it is not one.
|
|
33
|
+
*/
|
|
34
|
+
export declare const getProblemChannelParams: (channel: string) => {
|
|
35
|
+
problemKey: string;
|
|
36
|
+
role: ProblemChannelRole;
|
|
37
|
+
} | null;
|
|
@@ -63,8 +63,25 @@ export interface UnsubscribeUserNotificationWebSocketEventDto extends WebsocketS
|
|
|
63
63
|
event: WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
|
|
64
64
|
userKey: string;
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Scope of a submissions table: the judging start/end of the submissions of one problem, one contest or one user.
|
|
68
|
+
* Exactly one of the keys is set.
|
|
69
|
+
*/
|
|
70
|
+
export type SubmissionsJudgingScope = {
|
|
71
|
+
problemKey: string;
|
|
72
|
+
} | {
|
|
73
|
+
contestKey: string;
|
|
74
|
+
} | {
|
|
75
|
+
userId: string;
|
|
76
|
+
};
|
|
77
|
+
export type SubscribeSubmissionsJudgingWebSocketEventDto = WebsocketSubscription & {
|
|
78
|
+
event: WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_JUDGING;
|
|
79
|
+
} & SubmissionsJudgingScope;
|
|
80
|
+
export type UnsubscribeSubmissionsJudgingWebSocketEventDto = WebsocketSubscription & {
|
|
81
|
+
event: WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_JUDGING;
|
|
82
|
+
} & SubmissionsJudgingScope;
|
|
83
|
+
export type WebSocketSubscribeEventDto = SubscribeCodeRunStatusWebSocketEventDto | SubscribeSubmissionRunStatusWebSocketEventDto | SubscribeGetDataWebSocketEventDto | SubscribeProblemCrawledWebSocketEventDto | SubscribeSubmissionsCrawlWebSocketEventDto | SubscribeContestChangesWebSocketEventDto | SubscribeUserNotificationWebsocketEventDto | SubscribeSubmissionsJudgingWebSocketEventDto;
|
|
84
|
+
export type WebSocketUnsubscribeEventDto = UnsubscribeCodeRunStatusWebSocketEventDto | UnsubscribeSubmissionRunStatusWebSocketEventDto | UnsubscribeGetDataWebSocketEventDto | UnsubscribeProblemCrawledWebSocketEventDto | UnsubscribeSubmissionsCrawlWebSocketEventDto | UnsubscribeContestChangesWebSocketEventDto | UnsubscribeUserNotificationWebSocketEventDto | UnsubscribeSubmissionsJudgingWebSocketEventDto;
|
|
68
85
|
export interface WebSocketResponse {
|
|
69
86
|
event: WebSocketResponseEvent;
|
|
70
87
|
key: WebSocketResponseEventKey;
|
|
@@ -86,6 +103,23 @@ export interface SubmissionRunStatusWebSocketResponseEventDto extends WebSocketR
|
|
|
86
103
|
testInfo?: TestInfo;
|
|
87
104
|
shouldValidateContest: boolean;
|
|
88
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Start (`judging: true`, status RECEIVED) and end (`judging: false`, status COMPLETED / FAILED) of the judging of a
|
|
108
|
+
* submission, also on rejudges. Published on the channels of the tables that list it (problem / contest / user), so a
|
|
109
|
+
* table listens to one channel and only attaches `CHANNEL_SUBMISSION` (the case by case progress) of the submissions
|
|
110
|
+
* on screen that are being judged. The case by case events keep arriving as `SubmissionRunStatusWebSocketResponseEventDto`.
|
|
111
|
+
*/
|
|
112
|
+
export interface SubmissionJudgingWebSocketResponseEventDto extends WebSocketResponse {
|
|
113
|
+
event: WebSocketResponseEvent.SUBMISSION_JUDGING;
|
|
114
|
+
submitId: string;
|
|
115
|
+
problemKey: string;
|
|
116
|
+
contestKey: string | null;
|
|
117
|
+
userId: string;
|
|
118
|
+
judging: boolean;
|
|
119
|
+
status: SubmissionRunStatus;
|
|
120
|
+
verdict: ProblemVerdict;
|
|
121
|
+
points: number;
|
|
122
|
+
}
|
|
89
123
|
export interface UserMessageWebSocketResponseEventDto extends WebSocketResponse {
|
|
90
124
|
event: WebSocketResponseEvent.USER_MESSAGE;
|
|
91
125
|
user: UserOrganizationBasicInfoResponseDto;
|
|
@@ -179,7 +213,7 @@ export interface UserNotificationContestClarificationWebSocketResponseEventDto e
|
|
|
179
213
|
contestKey: string;
|
|
180
214
|
};
|
|
181
215
|
}
|
|
182
|
-
export type WebSocketResponseEventDto = CodeRunStatusWebSocketResponseEventDto | SubmissionRunStatusWebSocketResponseEventDto | UserMessageWebSocketResponseEventDto | SendDataEcsTaskDefinitionListWebSocketResponseEventDto | SendDataEcsTasksListWebSocketResponseEventDto | SendDataEc2InstancesListWebSocketResponseEventDto | SendDataSsmSessionsListWebSocketResponseEventDto | ProblemCrawledWebSocketResponseEventDto | SubmissionsCrawlWebSocketResponseEventDto | ContestChangesWebSocketResponseEventDto | SendDataRunCommandWebSocketResponseEventDto | UserNotificationSubmissionWebSocketResponseEventDto | UserNotificationContestClarificationWebSocketResponseEventDto;
|
|
216
|
+
export type WebSocketResponseEventDto = CodeRunStatusWebSocketResponseEventDto | SubmissionRunStatusWebSocketResponseEventDto | UserMessageWebSocketResponseEventDto | SendDataEcsTaskDefinitionListWebSocketResponseEventDto | SendDataEcsTasksListWebSocketResponseEventDto | SendDataEc2InstancesListWebSocketResponseEventDto | SendDataSsmSessionsListWebSocketResponseEventDto | ProblemCrawledWebSocketResponseEventDto | SubmissionsCrawlWebSocketResponseEventDto | ContestChangesWebSocketResponseEventDto | SendDataRunCommandWebSocketResponseEventDto | UserNotificationSubmissionWebSocketResponseEventDto | UserNotificationContestClarificationWebSocketResponseEventDto | SubmissionJudgingWebSocketResponseEventDto;
|
|
183
217
|
/**
|
|
184
218
|
* Message sent by the backend producers to the websocket SQS queue:
|
|
185
219
|
* the producer (trusted, with access to the DB) decides the Ably channels where the event is published.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CodeRunStatusWebSocketResponseEventDto, ContestChangesWebSocketResponseEventDto, ProblemCrawledWebSocketResponseEventDto, SendDataEc2InstancesListWebSocketResponseEventDto, SendDataEcsTaskDefinitionListWebSocketResponseEventDto, SendDataEcsTasksListWebSocketResponseEventDto, SendDataRunCommandWebSocketResponseEventDto, SendDataSsmSessionsListWebSocketResponseEventDto, SendDataWebSocketResponseEventDto, SubmissionRunStatusWebSocketResponseEventDto, SubmissionsCrawlWebSocketResponseEventDto, SubscribeCodeRunStatusWebSocketEventDto, SubscribeContestChangesWebSocketEventDto, SubscribeGetDataWebSocketEventDto, SubscribeProblemCrawledWebSocketEventDto, SubscribeSubmissionRunStatusWebSocketEventDto, SubscribeSubmissionsCrawlWebSocketEventDto, SubscribeUserNotificationWebsocketEventDto, UnsubscribeCodeRunStatusWebSocketEventDto, UnsubscribeContestChangesWebSocketEventDto, UnsubscribeGetDataWebSocketEventDto, UnsubscribeProblemCrawledWebSocketEventDto, UnsubscribeSubmissionRunStatusWebSocketEventDto, UnsubscribeSubmissionsCrawlWebSocketEventDto, UnsubscribeUserNotificationWebSocketEventDto, UserMessageWebSocketResponseEventDto, UserNotificationContestClarificationWebSocketResponseEventDto, UserNotificationSubmissionWebSocketResponseEventDto, UserNotificationWebSocketResponseEventDto, WebSocketChannelsMessageDto, WebSocketResponseEventDto, WebSocketSubscribeEventDto, WebSocketUnsubscribeEventDto } from '../dto';
|
|
1
|
+
import { CodeRunStatusWebSocketResponseEventDto, ContestChangesWebSocketResponseEventDto, ProblemCrawledWebSocketResponseEventDto, SendDataEc2InstancesListWebSocketResponseEventDto, SendDataEcsTaskDefinitionListWebSocketResponseEventDto, SendDataEcsTasksListWebSocketResponseEventDto, SendDataRunCommandWebSocketResponseEventDto, SendDataSsmSessionsListWebSocketResponseEventDto, SendDataWebSocketResponseEventDto, SubmissionJudgingWebSocketResponseEventDto, SubmissionRunStatusWebSocketResponseEventDto, SubmissionsCrawlWebSocketResponseEventDto, SubmissionsJudgingScope, SubscribeCodeRunStatusWebSocketEventDto, SubscribeContestChangesWebSocketEventDto, SubscribeGetDataWebSocketEventDto, SubscribeProblemCrawledWebSocketEventDto, SubscribeSubmissionRunStatusWebSocketEventDto, SubscribeSubmissionsCrawlWebSocketEventDto, SubscribeSubmissionsJudgingWebSocketEventDto, SubscribeUserNotificationWebsocketEventDto, UnsubscribeCodeRunStatusWebSocketEventDto, UnsubscribeContestChangesWebSocketEventDto, UnsubscribeGetDataWebSocketEventDto, UnsubscribeProblemCrawledWebSocketEventDto, UnsubscribeSubmissionRunStatusWebSocketEventDto, UnsubscribeSubmissionsCrawlWebSocketEventDto, UnsubscribeSubmissionsJudgingWebSocketEventDto, UnsubscribeUserNotificationWebSocketEventDto, UserMessageWebSocketResponseEventDto, UserNotificationContestClarificationWebSocketResponseEventDto, UserNotificationSubmissionWebSocketResponseEventDto, UserNotificationWebSocketResponseEventDto, WebSocketChannelsMessageDto, WebSocketResponseEventDto, WebSocketSubscribeEventDto, WebSocketUnsubscribeEventDto } from '../dto';
|
|
2
2
|
import { ClientId, WebSocketResponseEvent, WebSocketResponseEventKey } from '../types';
|
|
3
3
|
export declare const isWebsocketSubscription: (event: any) => event is WebSocketSubscribeEventDto | WebSocketUnsubscribeEventDto;
|
|
4
4
|
export declare const isSubscribeCodeRunStatusWebSocketEventDto: (event: any) => event is SubscribeCodeRunStatusWebSocketEventDto;
|
|
@@ -15,9 +15,16 @@ export declare const isSubscribeContestChangesWebSocketEventDto: (event: any) =>
|
|
|
15
15
|
export declare const isUnsubscribeContestChangesWebSocketEventDto: (event: any) => event is UnsubscribeContestChangesWebSocketEventDto;
|
|
16
16
|
export declare const isSubscribeUserNotificationWebSocketEventDto: (event: any) => event is SubscribeUserNotificationWebsocketEventDto;
|
|
17
17
|
export declare const isUnsubscribeUserNotificationWebSocketEventDto: (event: any) => event is UnsubscribeUserNotificationWebSocketEventDto;
|
|
18
|
+
/**
|
|
19
|
+
* Exactly one of `problemKey` / `contestKey` / `userId` is set.
|
|
20
|
+
*/
|
|
21
|
+
export declare const isSubmissionsJudgingScope: (scope: any) => scope is SubmissionsJudgingScope;
|
|
22
|
+
export declare const isSubscribeSubmissionsJudgingWebSocketEventDto: (event: any) => event is SubscribeSubmissionsJudgingWebSocketEventDto;
|
|
23
|
+
export declare const isUnsubscribeSubmissionsJudgingWebSocketEventDto: (event: any) => event is UnsubscribeSubmissionsJudgingWebSocketEventDto;
|
|
18
24
|
export declare const isWebSocketResponseEventDto: (event: any) => event is WebSocketResponseEventDto;
|
|
19
25
|
export declare const isCodeRunStatusMessageWebSocketResponseEventDto: (event: any) => event is CodeRunStatusWebSocketResponseEventDto;
|
|
20
26
|
export declare const isSubmissionRunStatusMessageWebSocketResponseEventDto: (event: any) => event is SubmissionRunStatusWebSocketResponseEventDto;
|
|
27
|
+
export declare const isSubmissionJudgingWebSocketResponseEventDto: (event: any) => event is SubmissionJudgingWebSocketResponseEventDto;
|
|
21
28
|
export declare const isUserMessageWebSocketResponseEventDto: (event: any) => event is UserMessageWebSocketResponseEventDto;
|
|
22
29
|
export declare const isSendDataWebSocketResponseEventDto: (event: any) => event is SendDataWebSocketResponseEventDto;
|
|
23
30
|
export declare const isSendDataEcsTaskDefinitionListWebSocketResponseEventDto: (event: any) => event is SendDataEcsTaskDefinitionListWebSocketResponseEventDto;
|
|
@@ -49,3 +56,7 @@ export declare const getChannelOfWebSocketSubscribeEvent: (event: WebSocketSubsc
|
|
|
49
56
|
* Contest whose role channels the client needs (the API grants them when the token is requested with this contest).
|
|
50
57
|
*/
|
|
51
58
|
export declare const getContestKeyOfWebSocketSubscribeEvent: (event: WebSocketSubscribeEventDto) => string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Problem whose role channels the client needs (the API grants them when the token is requested with this problem).
|
|
61
|
+
*/
|
|
62
|
+
export declare const getProblemKeyOfWebSocketSubscribeEvent: (event: WebSocketSubscribeEventDto) => string | null;
|
|
@@ -17,7 +17,9 @@ export declare enum WebSocketSubscriptionEvent {
|
|
|
17
17
|
SUBSCRIBE_CONTEST_CHANGES = "SUBSCRIBE_CONTEST_CHANGES",
|
|
18
18
|
UNSUBSCRIBE_CONTEST_CHANGES = "UNSUBSCRIBE_CONTEST_CHANGES",
|
|
19
19
|
SUBSCRIBE_USER_NOTIFICATION = "SUBSCRIBE_USER_NOTIFICATION",
|
|
20
|
-
UNSUBSCRIBE_USER_NOTIFICATION = "UNSUBSCRIBE_USER_NOTIFICATION"
|
|
20
|
+
UNSUBSCRIBE_USER_NOTIFICATION = "UNSUBSCRIBE_USER_NOTIFICATION",
|
|
21
|
+
SUBSCRIBE_SUBMISSIONS_JUDGING = "SUBSCRIBE_SUBMISSIONS_JUDGING",
|
|
22
|
+
UNSUBSCRIBE_SUBMISSIONS_JUDGING = "UNSUBSCRIBE_SUBMISSIONS_JUDGING"
|
|
21
23
|
}
|
|
22
24
|
export declare enum WebSocketResponseEvent {
|
|
23
25
|
CODE_RUN_STATUS = "CODE_RUN_STATUS",
|
|
@@ -34,7 +36,8 @@ export declare enum WebSocketResponseEvent {
|
|
|
34
36
|
CONTEST_CHANGES = "CONTEST_CHANGES",
|
|
35
37
|
USER_NOTIFICATION_ = "USER_NOTIFICATION_",
|
|
36
38
|
USER_NOTIFICATION_SUBMISSION = "USER_NOTIFICATION_SUBMISSION",
|
|
37
|
-
USER_NOTIFICATION_CONTEST_CLARIFICATION = "USER_NOTIFICATION_CONTEST_CLARIFICATION"
|
|
39
|
+
USER_NOTIFICATION_CONTEST_CLARIFICATION = "USER_NOTIFICATION_CONTEST_CLARIFICATION",
|
|
40
|
+
SUBMISSION_JUDGING = "SUBMISSION_JUDGING"
|
|
38
41
|
}
|
|
39
42
|
export type ClientId = `${RecordId}|${string}`;
|
|
40
43
|
export type WebSocketResponseEventKey = `${WebSocketResponseEvent}-${ClientId}-${string}`;
|
|
@@ -51,6 +54,23 @@ export declare enum ContestChannelRole {
|
|
|
51
54
|
GUESTS = "guests",
|
|
52
55
|
SPECTATORS = "spectators"
|
|
53
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Roles of a problem, the ones computed by `getProblemAccessPermissions` (backend).
|
|
59
|
+
* Each role has its own Ably channel: `problem:{problemKey}:{role}` (see `CHANNEL_PROBLEM`).
|
|
60
|
+
*/
|
|
61
|
+
export declare enum ProblemChannelRole {
|
|
62
|
+
ADMINISTRATORS = "administrators",
|
|
63
|
+
MANAGERS = "managers",
|
|
64
|
+
SPECTATORS = "spectators"
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Roles of the public channels of a user: `user:{userId}:{role}` (see `CHANNEL_USER_ROLE`).
|
|
68
|
+
* There are no per-user permissions: `spectators` is everyone who can list the submissions of the user.
|
|
69
|
+
* The private channel of the user is `user:{userId}` (see `CHANNEL_USER`).
|
|
70
|
+
*/
|
|
71
|
+
export declare enum UserChannelRole {
|
|
72
|
+
SPECTATORS = "spectators"
|
|
73
|
+
}
|
|
54
74
|
export type InfoLogCaseStatus = {
|
|
55
75
|
inputKey: string;
|
|
56
76
|
out: string;
|