@jpetit/toolkit 3.0.23 → 3.1.2
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/assets/prompts/creators/create-solution.tpl.txt +10 -0
- package/assets/prompts/creators/create-statement.tpl.txt +21 -0
- package/assets/prompts/creators/create-translation.tpl.txt +5 -0
- package/assets/prompts/creators/private-test-cases.txt +6 -0
- package/assets/prompts/creators/sample-test-cases.txt +6 -0
- package/assets/prompts/creators/system-prompt.txt +2 -0
- package/assets/prompts/examples/statement-coda.tex +7 -0
- package/assets/prompts/examples/statement.tex +19 -0
- package/assets/prompts/generators/efficiency.md +41 -0
- package/assets/prompts/generators/hard.md +47 -0
- package/assets/prompts/generators/random.md +39 -0
- package/assets/prompts/proglangs/cc.md +3 -0
- package/assets/prompts/proglangs/py.md +40 -0
- package/lib/ai.ts +60 -4
- package/lib/cleaner.ts +24 -13
- package/lib/compilers/base.ts +70 -14
- package/lib/compilers/clojure.ts +21 -10
- package/lib/compilers/gcc.ts +4 -33
- package/lib/compilers/ghc.ts +4 -40
- package/lib/compilers/gxx.ts +4 -33
- package/lib/compilers/index.ts +9 -0
- package/lib/compilers/java.ts +105 -0
- package/lib/compilers/python3.ts +44 -37
- package/lib/compilers/run-clojure.ts +101 -0
- package/lib/compilers/run-haskell.ts +26 -22
- package/lib/compilers/run-python.ts +29 -35
- package/lib/compilers/rust.ts +39 -0
- package/lib/create-with-jutgeai.ts +407 -0
- package/lib/create-with-template.ts +55 -0
- package/lib/data.ts +6 -0
- package/lib/doctor.ts +86 -6
- package/lib/generate.ts +132 -290
- package/lib/helpers.ts +48 -0
- package/lib/inspector.ts +253 -0
- package/lib/jutge_api_client.ts +4631 -0
- package/lib/maker.ts +202 -289
- package/lib/settings.ts +26 -17
- package/lib/tui.ts +25 -15
- package/lib/types.ts +40 -5
- package/lib/upload.ts +216 -0
- package/lib/utils.ts +82 -14
- package/lib/versions.ts +46 -0
- package/package.json +50 -11
- package/toolkit/about.ts +43 -0
- package/toolkit/ai.ts +44 -18
- package/toolkit/check.ts +16 -0
- package/toolkit/clean.ts +16 -26
- package/toolkit/compilers.ts +4 -4
- package/toolkit/config.ts +91 -0
- package/toolkit/create.ts +30 -58
- package/toolkit/doctor.ts +15 -11
- package/toolkit/generate.ts +195 -98
- package/toolkit/index.ts +32 -21
- package/toolkit/make.ts +12 -48
- package/toolkit/upgrade.ts +9 -0
- package/toolkit/upload.ts +19 -0
- package/toolkit/create-jutge-ai.ts +0 -101
- package/toolkit/create-template.ts +0 -55
- package/toolkit/create-wizard.ts +0 -6
- package/toolkit/init.ts +0 -56
- package/toolkit/verify.ts +0 -19
|
@@ -0,0 +1,4631 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file has been automatically generated at 2025-12-27T15:56:42.672Z
|
|
3
|
+
*
|
|
4
|
+
* Name: Jutge API
|
|
5
|
+
* Version: 2.0.0
|
|
6
|
+
*
|
|
7
|
+
* Description: Jutge API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
12
|
+
|
|
13
|
+
// Models
|
|
14
|
+
|
|
15
|
+
export type CredentialsIn = {
|
|
16
|
+
email: string
|
|
17
|
+
password: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ExamCredentialsIn = {
|
|
21
|
+
email: string
|
|
22
|
+
password: string
|
|
23
|
+
exam: string
|
|
24
|
+
exam_password: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type CredentialsOut = {
|
|
28
|
+
token: string
|
|
29
|
+
expiration: string | string | string | number
|
|
30
|
+
user_uid: string
|
|
31
|
+
error: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type Time = {
|
|
35
|
+
full_time: string
|
|
36
|
+
int_timestamp: number
|
|
37
|
+
float_timestamp: number
|
|
38
|
+
time: string
|
|
39
|
+
date: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type HomepageStats = {
|
|
43
|
+
users: number
|
|
44
|
+
problems: number
|
|
45
|
+
submissions: number
|
|
46
|
+
exams: number
|
|
47
|
+
contests: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type ColorMapping = Record<string, Record<string, string>>
|
|
51
|
+
|
|
52
|
+
export type ApiVersion = {
|
|
53
|
+
version: string
|
|
54
|
+
mode: string
|
|
55
|
+
gitHash: string
|
|
56
|
+
gitBranch: string
|
|
57
|
+
gitDate: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type RequestInformation = {
|
|
61
|
+
url: string
|
|
62
|
+
ip: string
|
|
63
|
+
domain: string
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type Language = {
|
|
67
|
+
language_id: string
|
|
68
|
+
eng_name: string
|
|
69
|
+
own_name: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type Country = {
|
|
73
|
+
country_id: string
|
|
74
|
+
eng_name: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type Compiler = {
|
|
78
|
+
compiler_id: string
|
|
79
|
+
name: string
|
|
80
|
+
language: string
|
|
81
|
+
extension: string
|
|
82
|
+
description: string | null
|
|
83
|
+
version: string | null
|
|
84
|
+
flags1: string | null
|
|
85
|
+
flags2: string | null
|
|
86
|
+
type: string | null
|
|
87
|
+
warning: string | null
|
|
88
|
+
status: string | null
|
|
89
|
+
notes: string | null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type Driver = {
|
|
93
|
+
driver_id: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type Verdict = {
|
|
97
|
+
verdict_id: string
|
|
98
|
+
name: string
|
|
99
|
+
description: string
|
|
100
|
+
emoji: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type Proglang = {
|
|
104
|
+
proglang_id: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type AllTables = {
|
|
108
|
+
languages: Record<string, Language>
|
|
109
|
+
countries: Record<string, Country>
|
|
110
|
+
compilers: Record<string, Compiler>
|
|
111
|
+
drivers: Record<string, Driver>
|
|
112
|
+
verdicts: Record<string, Verdict>
|
|
113
|
+
proglangs: Record<string, Proglang>
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export type ProblemSummary = {
|
|
117
|
+
summary_1s: string
|
|
118
|
+
summary_1p: string
|
|
119
|
+
keywords: string
|
|
120
|
+
model: string
|
|
121
|
+
duration: number
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type SolutionTags = {
|
|
125
|
+
tags: string
|
|
126
|
+
model: string
|
|
127
|
+
duration: number
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type BriefAbstractProblem = {
|
|
131
|
+
problem_nm: string
|
|
132
|
+
author: string | null
|
|
133
|
+
author_email: string | null
|
|
134
|
+
public: number | null
|
|
135
|
+
official: number | null
|
|
136
|
+
compilers: string | null
|
|
137
|
+
driver_id: string | null
|
|
138
|
+
type: string | null
|
|
139
|
+
deprecation: string | null
|
|
140
|
+
created_at: string | string | string | number
|
|
141
|
+
updated_at: string | string | string | number
|
|
142
|
+
solution_tags: SolutionTags | null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export type BriefProblem = {
|
|
146
|
+
problem_id: string
|
|
147
|
+
problem_nm: string
|
|
148
|
+
language_id: string
|
|
149
|
+
title: string
|
|
150
|
+
original_language_id: string
|
|
151
|
+
translator: string | null
|
|
152
|
+
translator_email: string | null
|
|
153
|
+
checked: number | null
|
|
154
|
+
summary: ProblemSummary | null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type BriefProblemDict = Record<string, BriefProblem>
|
|
158
|
+
|
|
159
|
+
export type AbstractProblem = {
|
|
160
|
+
problem_nm: string
|
|
161
|
+
author: string | null
|
|
162
|
+
author_email: string | null
|
|
163
|
+
public: number | null
|
|
164
|
+
official: number | null
|
|
165
|
+
compilers: string | null
|
|
166
|
+
driver_id: string | null
|
|
167
|
+
type: string | null
|
|
168
|
+
deprecation: string | null
|
|
169
|
+
created_at: string | string | string | number
|
|
170
|
+
updated_at: string | string | string | number
|
|
171
|
+
solution_tags: SolutionTags | null
|
|
172
|
+
problems: BriefProblemDict
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export type AbstractProblemSuppl = {
|
|
176
|
+
compilers_with_ac: string[]
|
|
177
|
+
proglangs_with_ac: string[]
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export type ProblemSuppl = {
|
|
181
|
+
compilers_with_ac: string[]
|
|
182
|
+
proglangs_with_ac: string[]
|
|
183
|
+
official_solution_checks: Record<string, boolean>
|
|
184
|
+
handler: any
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export type Problem = {
|
|
188
|
+
problem_id: string
|
|
189
|
+
problem_nm: string
|
|
190
|
+
language_id: string
|
|
191
|
+
title: string
|
|
192
|
+
original_language_id: string
|
|
193
|
+
translator: string | null
|
|
194
|
+
translator_email: string | null
|
|
195
|
+
checked: number | null
|
|
196
|
+
summary: ProblemSummary | null
|
|
197
|
+
abstract_problem: BriefAbstractProblem
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export type Testcase = {
|
|
201
|
+
name: string
|
|
202
|
+
input_b64: string
|
|
203
|
+
correct_b64: string
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type ProblemRich = {
|
|
207
|
+
problem_id: string
|
|
208
|
+
problem_nm: string
|
|
209
|
+
language_id: string
|
|
210
|
+
title: string
|
|
211
|
+
original_language_id: string
|
|
212
|
+
translator: string | null
|
|
213
|
+
translator_email: string | null
|
|
214
|
+
checked: number | null
|
|
215
|
+
summary: ProblemSummary | null
|
|
216
|
+
abstract_problem: BriefAbstractProblem
|
|
217
|
+
sample_testcases: Testcase[]
|
|
218
|
+
html_statement: string
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export type SearchResult = {
|
|
222
|
+
problem_nm: string
|
|
223
|
+
score: number
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export type SearchResults = SearchResult[]
|
|
227
|
+
|
|
228
|
+
export type AllKeys = {
|
|
229
|
+
problems: string[]
|
|
230
|
+
enrolled_courses: string[]
|
|
231
|
+
available_courses: string[]
|
|
232
|
+
lists: string[]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export type Profile = {
|
|
236
|
+
user_uid: string
|
|
237
|
+
email: string
|
|
238
|
+
name: string
|
|
239
|
+
username: string | null
|
|
240
|
+
nickname: string | null
|
|
241
|
+
webpage: string | null
|
|
242
|
+
description: string | null
|
|
243
|
+
affiliation: string | null
|
|
244
|
+
birth_year: number | null
|
|
245
|
+
max_subsxhour: number
|
|
246
|
+
max_subsxday: number
|
|
247
|
+
administrator: number
|
|
248
|
+
instructor: number
|
|
249
|
+
parent_email: string | null
|
|
250
|
+
country_id: string | null
|
|
251
|
+
timezone_id: string
|
|
252
|
+
compiler_id: string | null
|
|
253
|
+
language_id: string | null
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export type NewProfile = {
|
|
257
|
+
name: string
|
|
258
|
+
birth_year: number
|
|
259
|
+
nickname: string
|
|
260
|
+
webpage: string
|
|
261
|
+
affiliation: string
|
|
262
|
+
description: string
|
|
263
|
+
country_id: string
|
|
264
|
+
timezone_id: string
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export type NewPassword = {
|
|
268
|
+
oldPassword: string
|
|
269
|
+
newPassword: string
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export type DateValue = {
|
|
273
|
+
date: number
|
|
274
|
+
value: number
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export type HeatmapCalendar = DateValue[]
|
|
278
|
+
|
|
279
|
+
export type Distribution = Record<string, number>
|
|
280
|
+
|
|
281
|
+
export type AllDistributions = {
|
|
282
|
+
verdicts: Distribution
|
|
283
|
+
compilers: Distribution
|
|
284
|
+
proglangs: Distribution
|
|
285
|
+
submissions_by_hour: Distribution
|
|
286
|
+
submissions_by_weekday: Distribution
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export type Dashboard = {
|
|
290
|
+
stats: Distribution
|
|
291
|
+
heatmap: HeatmapCalendar
|
|
292
|
+
distributions: AllDistributions
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export type Submission = {
|
|
296
|
+
problem_id: string
|
|
297
|
+
submission_id: string
|
|
298
|
+
compiler_id: string
|
|
299
|
+
annotation: string | null
|
|
300
|
+
state: string
|
|
301
|
+
time_in: string | string | string | number
|
|
302
|
+
veredict: string | null
|
|
303
|
+
veredict_info: string | null
|
|
304
|
+
veredict_publics: string | null
|
|
305
|
+
ok_publics_but_wrong: number
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export type NewSubmissionIn = {
|
|
309
|
+
problem_id: string
|
|
310
|
+
compiler_id: string
|
|
311
|
+
annotation: string
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export type NewSubmissionOut = {
|
|
315
|
+
submission_id: string
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export type SubmissionAnalysis = {
|
|
319
|
+
testcase: string
|
|
320
|
+
execution: string
|
|
321
|
+
verdict: string
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export type TestcaseAnalysis = {
|
|
325
|
+
testcase: string
|
|
326
|
+
execution: string
|
|
327
|
+
verdict: string
|
|
328
|
+
input_b64: string
|
|
329
|
+
output_b64: string
|
|
330
|
+
expected_b64: string
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export type PublicProfile = {
|
|
334
|
+
email: string
|
|
335
|
+
name: string
|
|
336
|
+
username: string | null
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export type BriefCourse = {
|
|
340
|
+
course_nm: string
|
|
341
|
+
title: string | null
|
|
342
|
+
description: string | null
|
|
343
|
+
annotation: string | null
|
|
344
|
+
public: number
|
|
345
|
+
official: number
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export type Course = {
|
|
349
|
+
course_nm: string
|
|
350
|
+
title: string | null
|
|
351
|
+
description: string | null
|
|
352
|
+
annotation: string | null
|
|
353
|
+
public: number
|
|
354
|
+
official: number
|
|
355
|
+
owner: PublicProfile
|
|
356
|
+
lists: string[]
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export type ListItem = {
|
|
360
|
+
problem_nm: string | null
|
|
361
|
+
description: string | null
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export type BriefList = {
|
|
365
|
+
list_nm: string
|
|
366
|
+
title: string | null
|
|
367
|
+
description: string | null
|
|
368
|
+
annotation: string | null
|
|
369
|
+
public: number
|
|
370
|
+
official: number
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export type List = {
|
|
374
|
+
list_nm: string
|
|
375
|
+
title: string | null
|
|
376
|
+
description: string | null
|
|
377
|
+
annotation: string | null
|
|
378
|
+
public: number
|
|
379
|
+
official: number
|
|
380
|
+
items: ListItem[]
|
|
381
|
+
owner: PublicProfile
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export type ReadyExam = {
|
|
385
|
+
exam_key: string
|
|
386
|
+
title: string
|
|
387
|
+
place: string
|
|
388
|
+
description: string
|
|
389
|
+
exp_time_start: string | string | string | number
|
|
390
|
+
running_time: number
|
|
391
|
+
contest: boolean
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export type RunningExamProblem = {
|
|
395
|
+
problem_nm: string
|
|
396
|
+
icon: string | null
|
|
397
|
+
caption: string | null
|
|
398
|
+
weight: number | null
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export type RunningExamDocument = {
|
|
402
|
+
document_nm: string
|
|
403
|
+
title: string
|
|
404
|
+
description: string
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export type RunningExam = {
|
|
408
|
+
title: string
|
|
409
|
+
description: string
|
|
410
|
+
instructions: string
|
|
411
|
+
time_start: string | string | string | number | null
|
|
412
|
+
exp_time_start: string | string | string | number
|
|
413
|
+
running_time: number
|
|
414
|
+
contest: number
|
|
415
|
+
problems: RunningExamProblem[]
|
|
416
|
+
compilers: string[]
|
|
417
|
+
documents: RunningExamDocument[]
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export type AbstractStatus = {
|
|
421
|
+
problem_nm: string
|
|
422
|
+
nb_submissions: number
|
|
423
|
+
nb_pending_submissions: number
|
|
424
|
+
nb_accepted_submissions: number
|
|
425
|
+
nb_rejected_submissions: number
|
|
426
|
+
nb_scored_submissions: number
|
|
427
|
+
status: string
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export type Status = {
|
|
431
|
+
problem_id: string
|
|
432
|
+
problem_nm: string
|
|
433
|
+
nb_submissions: number
|
|
434
|
+
nb_pending_submissions: number
|
|
435
|
+
nb_accepted_submissions: number
|
|
436
|
+
nb_rejected_submissions: number
|
|
437
|
+
nb_scored_submissions: number
|
|
438
|
+
status: string
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export type Award = {
|
|
442
|
+
award_id: string
|
|
443
|
+
time: string | string | string | number
|
|
444
|
+
type: string
|
|
445
|
+
icon: string
|
|
446
|
+
title: string
|
|
447
|
+
info: string
|
|
448
|
+
youtube: string | null
|
|
449
|
+
submission: Submission | null
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export type BriefAward = {
|
|
453
|
+
award_id: string
|
|
454
|
+
time: string | string | string | number
|
|
455
|
+
type: string
|
|
456
|
+
icon: string
|
|
457
|
+
title: string
|
|
458
|
+
info: string
|
|
459
|
+
youtube: string | null
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export type Document = {
|
|
463
|
+
document_nm: string
|
|
464
|
+
title: string
|
|
465
|
+
description: string
|
|
466
|
+
created_at: string | string | string | number
|
|
467
|
+
updated_at: string | string | string | number
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export type DocumentCreation = {
|
|
471
|
+
document_nm: string
|
|
472
|
+
title: string
|
|
473
|
+
description: string
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export type DocumentUpdate = DocumentCreation
|
|
477
|
+
|
|
478
|
+
export type InstructorBriefList = {
|
|
479
|
+
list_nm: string
|
|
480
|
+
title: string
|
|
481
|
+
description: string
|
|
482
|
+
annotation: string
|
|
483
|
+
official: number
|
|
484
|
+
public: number
|
|
485
|
+
created_at: string | string | string | number
|
|
486
|
+
updated_at: string | string | string | number
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export type InstructorListItem = {
|
|
490
|
+
problem_nm: string | null
|
|
491
|
+
description: string | null
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export type InstructorListItems = InstructorListItem[]
|
|
495
|
+
|
|
496
|
+
export type InstructorList = {
|
|
497
|
+
list_nm: string
|
|
498
|
+
title: string
|
|
499
|
+
description: string
|
|
500
|
+
annotation: string
|
|
501
|
+
official: number
|
|
502
|
+
public: number
|
|
503
|
+
created_at: string | string | string | number
|
|
504
|
+
updated_at: string | string | string | number
|
|
505
|
+
items: InstructorListItems
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export type InstructorListCreation = {
|
|
509
|
+
list_nm: string
|
|
510
|
+
title: string
|
|
511
|
+
description: string
|
|
512
|
+
annotation: string
|
|
513
|
+
official: number
|
|
514
|
+
public: number
|
|
515
|
+
items: InstructorListItems
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export type InstructorListUpdate = InstructorListCreation
|
|
519
|
+
|
|
520
|
+
export type InstructorBriefCourse = {
|
|
521
|
+
course_nm: string
|
|
522
|
+
title: string
|
|
523
|
+
description: string
|
|
524
|
+
annotation: string
|
|
525
|
+
official: number
|
|
526
|
+
public: number
|
|
527
|
+
created_at: string | string | string | number
|
|
528
|
+
updated_at: string | string | string | number
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
export type CourseMembers = {
|
|
532
|
+
invited: string[]
|
|
533
|
+
enrolled: string[]
|
|
534
|
+
pending: string[]
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export type InstructorCourse = {
|
|
538
|
+
course_nm: string
|
|
539
|
+
title: string
|
|
540
|
+
description: string
|
|
541
|
+
annotation: string
|
|
542
|
+
official: number
|
|
543
|
+
public: number
|
|
544
|
+
created_at: string | string | string | number
|
|
545
|
+
updated_at: string | string | string | number
|
|
546
|
+
lists: string[]
|
|
547
|
+
students: CourseMembers
|
|
548
|
+
tutors: CourseMembers
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export type StudentProfile = {
|
|
552
|
+
name: string
|
|
553
|
+
email: string
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export type InstructorCourseCreation = {
|
|
557
|
+
course_nm: string
|
|
558
|
+
title: string
|
|
559
|
+
description: string
|
|
560
|
+
annotation: string
|
|
561
|
+
official: number
|
|
562
|
+
public: number
|
|
563
|
+
lists: string[] | null
|
|
564
|
+
students: CourseMembers | null
|
|
565
|
+
tutors: CourseMembers | null
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
export type InstructorCourseUpdate = {
|
|
569
|
+
course_nm: string
|
|
570
|
+
title: string | null
|
|
571
|
+
description: string | null
|
|
572
|
+
annotation: string | null
|
|
573
|
+
official: number | null
|
|
574
|
+
public: number | null
|
|
575
|
+
lists: string[] | null
|
|
576
|
+
students: CourseMembers | null
|
|
577
|
+
tutors: CourseMembers | null
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
export type InstructorExamCourse = {
|
|
581
|
+
course_nm: string
|
|
582
|
+
title: string
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export type InstructorExamDocument = RunningExamDocument
|
|
586
|
+
|
|
587
|
+
export type InstructorExamCompiler = {
|
|
588
|
+
compiler_id: string
|
|
589
|
+
name: string
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export type InstructorExamProblem = {
|
|
593
|
+
problem_nm: string
|
|
594
|
+
weight: number | null
|
|
595
|
+
icon: string | null
|
|
596
|
+
caption: string | null
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
export type InstructorExamStudent = {
|
|
600
|
+
email: string
|
|
601
|
+
name: string | null
|
|
602
|
+
code: string | null
|
|
603
|
+
restricted: number
|
|
604
|
+
annotation: string | null
|
|
605
|
+
result: string | null
|
|
606
|
+
finished: number
|
|
607
|
+
banned: number
|
|
608
|
+
reason_ban: string | null
|
|
609
|
+
inc: number | null
|
|
610
|
+
reason_inc: string | null
|
|
611
|
+
taken_exam: number
|
|
612
|
+
emergency_password: string | null
|
|
613
|
+
invited: number
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
export type InstructorExamCreation = {
|
|
617
|
+
exam_nm: string
|
|
618
|
+
course_nm: string
|
|
619
|
+
title: string
|
|
620
|
+
exp_time_start: string | string | string | number
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export type InstructorExamUpdate = {
|
|
624
|
+
exam_nm: string
|
|
625
|
+
course_nm: string
|
|
626
|
+
title: string
|
|
627
|
+
place: string
|
|
628
|
+
code: string
|
|
629
|
+
description: string
|
|
630
|
+
time_start: string | string | string | number | null
|
|
631
|
+
exp_time_start: string | string | string | number
|
|
632
|
+
running_time: number
|
|
633
|
+
visible_submissions: number
|
|
634
|
+
started_by: string | null
|
|
635
|
+
contest: number
|
|
636
|
+
instructions: string
|
|
637
|
+
avatars: string | null
|
|
638
|
+
anonymous: number
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export type InstructorNewExamStudent = {
|
|
642
|
+
email: string
|
|
643
|
+
invited: number
|
|
644
|
+
restricted: number
|
|
645
|
+
code: string
|
|
646
|
+
emergency_password: string
|
|
647
|
+
annotation: string
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
export type InstructorExamSubmissionsOptions = {
|
|
651
|
+
problems: string
|
|
652
|
+
include_source: boolean
|
|
653
|
+
include_pdf: boolean
|
|
654
|
+
include_metadata: boolean
|
|
655
|
+
only_last: boolean
|
|
656
|
+
font_size: number
|
|
657
|
+
layout: string
|
|
658
|
+
obscure_private_testcases_names: boolean
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
export type Pack = {
|
|
662
|
+
message: string
|
|
663
|
+
href: string
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
export type InstructorBriefExam = {
|
|
667
|
+
exam_nm: string
|
|
668
|
+
title: string
|
|
669
|
+
place: string | null
|
|
670
|
+
description: string | null
|
|
671
|
+
code: string | null
|
|
672
|
+
time_start: string | string | string | number | null
|
|
673
|
+
exp_time_start: string | string | string | number
|
|
674
|
+
running_time: number
|
|
675
|
+
visible_submissions: number
|
|
676
|
+
started_by: string | null
|
|
677
|
+
contest: number
|
|
678
|
+
instructions: string | null
|
|
679
|
+
avatars: string | null
|
|
680
|
+
anonymous: number
|
|
681
|
+
course: InstructorExamCourse
|
|
682
|
+
created_at: string | string | string | number
|
|
683
|
+
updated_at: string | string | string | number
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export type InstructorExam = {
|
|
687
|
+
exam_nm: string
|
|
688
|
+
title: string
|
|
689
|
+
place: string | null
|
|
690
|
+
description: string | null
|
|
691
|
+
code: string | null
|
|
692
|
+
time_start: string | string | string | number | null
|
|
693
|
+
exp_time_start: string | string | string | number
|
|
694
|
+
running_time: number
|
|
695
|
+
visible_submissions: number
|
|
696
|
+
started_by: string | null
|
|
697
|
+
contest: number
|
|
698
|
+
instructions: string | null
|
|
699
|
+
avatars: string | null
|
|
700
|
+
anonymous: number
|
|
701
|
+
course: InstructorExamCourse
|
|
702
|
+
created_at: string | string | string | number
|
|
703
|
+
updated_at: string | string | string | number
|
|
704
|
+
documents: RunningExamDocument[]
|
|
705
|
+
compilers: InstructorExamCompiler[]
|
|
706
|
+
problems: InstructorExamProblem[]
|
|
707
|
+
students: InstructorExamStudent[]
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
export type ExamStatisticsEntry = {
|
|
711
|
+
minute: number
|
|
712
|
+
ok: number
|
|
713
|
+
ko: number
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
export type ExamStatistics = {
|
|
717
|
+
submissions: Record<string, Record<string, number>>
|
|
718
|
+
statuses: Record<string, Record<string, number>>
|
|
719
|
+
timeline: ExamStatisticsEntry[]
|
|
720
|
+
compilers: Record<string, Record<string, number>>
|
|
721
|
+
proglangs: Record<string, Record<string, number>>
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
export type RankingResult = {
|
|
725
|
+
problem_nm: string
|
|
726
|
+
submissions: number
|
|
727
|
+
verdict: string | null
|
|
728
|
+
score: number
|
|
729
|
+
time: number
|
|
730
|
+
penalty: number
|
|
731
|
+
wrongs: number
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
export type RankingRow = {
|
|
735
|
+
position: number | null
|
|
736
|
+
name: string
|
|
737
|
+
avatar: string | null
|
|
738
|
+
score: number
|
|
739
|
+
time: number
|
|
740
|
+
invited: boolean
|
|
741
|
+
submissions: number
|
|
742
|
+
rankingResults: RankingResult[]
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
export type Ranking = RankingRow[]
|
|
746
|
+
|
|
747
|
+
export type WebStream = {
|
|
748
|
+
title: string
|
|
749
|
+
id: string
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
export type ProblemGenerationInfo = {
|
|
753
|
+
title: string
|
|
754
|
+
prompt: string
|
|
755
|
+
model: string
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
export type SubmissionQuery = {
|
|
759
|
+
email: string
|
|
760
|
+
problem_nm: string
|
|
761
|
+
problem_id: string
|
|
762
|
+
time: string | string | string | number
|
|
763
|
+
ip: string
|
|
764
|
+
verdict: string
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
export type SubmissionsQuery = SubmissionQuery[]
|
|
768
|
+
|
|
769
|
+
export type TagsDict = Record<string, string[]>
|
|
770
|
+
|
|
771
|
+
export type InstructorEntry = {
|
|
772
|
+
username: string
|
|
773
|
+
name: string
|
|
774
|
+
email: string
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
export type InstructorEntries = InstructorEntry[]
|
|
778
|
+
|
|
779
|
+
export type UserCreation = {
|
|
780
|
+
email: string
|
|
781
|
+
name: string
|
|
782
|
+
username: string
|
|
783
|
+
password: string
|
|
784
|
+
administrator: number
|
|
785
|
+
instructor: number
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
export type UserEmailAndName = {
|
|
789
|
+
email: string
|
|
790
|
+
name: string
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
export type UsersEmailsAndNames = UserEmailAndName[]
|
|
794
|
+
|
|
795
|
+
export type ProfileForAdmin = {
|
|
796
|
+
user_id: string
|
|
797
|
+
user_uid: string
|
|
798
|
+
email: string
|
|
799
|
+
name: string
|
|
800
|
+
username: string | null
|
|
801
|
+
nickname: string | null
|
|
802
|
+
webpage: string | null
|
|
803
|
+
description: string | null
|
|
804
|
+
affiliation: string | null
|
|
805
|
+
birth_year: number | null
|
|
806
|
+
max_subsxhour: number
|
|
807
|
+
max_subsxday: number
|
|
808
|
+
administrator: number
|
|
809
|
+
instructor: number
|
|
810
|
+
parent_email: string | null
|
|
811
|
+
country_id: string | null
|
|
812
|
+
timezone_id: string
|
|
813
|
+
compiler_id: string | null
|
|
814
|
+
language_id: string | null
|
|
815
|
+
locked: number
|
|
816
|
+
banned: number
|
|
817
|
+
nb_bans: number
|
|
818
|
+
reason: string | null
|
|
819
|
+
creation_date: string | string | string | number
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
export type DatabasesInfoItem = {
|
|
823
|
+
name: string
|
|
824
|
+
size: number
|
|
825
|
+
mtime: string | string | string | number
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
export type DatabasesInfo = DatabasesInfoItem[]
|
|
829
|
+
|
|
830
|
+
export type FreeDiskSpaceItem = {
|
|
831
|
+
disk: string
|
|
832
|
+
filesystem: string
|
|
833
|
+
size: string
|
|
834
|
+
used: string
|
|
835
|
+
available: string
|
|
836
|
+
use: string
|
|
837
|
+
mounted: string
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
export type NullableFreeDiskSpaceItem = FreeDiskSpaceItem | null
|
|
841
|
+
|
|
842
|
+
export type FreeDiskSpace = Record<string, NullableFreeDiskSpaceItem>
|
|
843
|
+
|
|
844
|
+
export type RecentConnectedUsers = {
|
|
845
|
+
latest_hour: number
|
|
846
|
+
latest_day: number
|
|
847
|
+
latest_week: number
|
|
848
|
+
latest_month: number
|
|
849
|
+
latest_year: number
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export type RecentSubmissions = {
|
|
853
|
+
latest_01_minutes: number
|
|
854
|
+
latest_05_minutes: number
|
|
855
|
+
latest_15_minutes: number
|
|
856
|
+
latest_60_minutes: number
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
export type RecentLoadAverages = {
|
|
860
|
+
latest_01_minutes: number
|
|
861
|
+
latest_05_minutes: number
|
|
862
|
+
latest_15_minutes: number
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
export type SubmissionsHistograms = {
|
|
866
|
+
latest_hour: number[]
|
|
867
|
+
latest_day: number[]
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export type Zombies = {
|
|
871
|
+
ies: number
|
|
872
|
+
pendings: number
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
export type AdminDashboard = {
|
|
876
|
+
databases_info: DatabasesInfo
|
|
877
|
+
free_disk_space: FreeDiskSpace
|
|
878
|
+
recent_load_averages: RecentLoadAverages
|
|
879
|
+
recent_connected_users: RecentConnectedUsers
|
|
880
|
+
recent_submissions: RecentSubmissions
|
|
881
|
+
submissions_histograms: SubmissionsHistograms
|
|
882
|
+
zombies: Zombies
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
export type UpcomingExam = {
|
|
886
|
+
exam_nm: string
|
|
887
|
+
title: string
|
|
888
|
+
username: string
|
|
889
|
+
email: string
|
|
890
|
+
exp_time_start: string | string | string | number
|
|
891
|
+
running_time: number
|
|
892
|
+
students: number
|
|
893
|
+
name: string
|
|
894
|
+
contest: number
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
export type UpcomingExams = UpcomingExam[]
|
|
898
|
+
|
|
899
|
+
export type SubmissionQueueItem = {
|
|
900
|
+
submission_uid: string
|
|
901
|
+
submission_id: string
|
|
902
|
+
problem_id: string
|
|
903
|
+
compiler_id: string
|
|
904
|
+
time_in: string | string | string | number
|
|
905
|
+
exam_id: string | null
|
|
906
|
+
veredict: string | null
|
|
907
|
+
user_id: string
|
|
908
|
+
user__name: string
|
|
909
|
+
problem__title: string
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
export type SubmissionQueueItems = SubmissionQueueItem[]
|
|
913
|
+
|
|
914
|
+
export type QueueQuery = {
|
|
915
|
+
verdicts: string[]
|
|
916
|
+
limit: number
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
export type UserRankingEntry = {
|
|
920
|
+
user_id: string
|
|
921
|
+
nickname: string | null
|
|
922
|
+
email: string
|
|
923
|
+
name: string
|
|
924
|
+
problems: number
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
export type UserRanking = UserRankingEntry[]
|
|
928
|
+
|
|
929
|
+
export type DateRange = {
|
|
930
|
+
start: string
|
|
931
|
+
end: string
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
export type TwoFloats = {
|
|
935
|
+
a: number
|
|
936
|
+
b: number
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
export type TwoInts = {
|
|
940
|
+
a: number
|
|
941
|
+
b: number
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
export type Name = {
|
|
945
|
+
name: string
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
export type SomeType = {
|
|
949
|
+
a: string
|
|
950
|
+
b: number
|
|
951
|
+
c: boolean
|
|
952
|
+
d: boolean
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Client types
|
|
956
|
+
|
|
957
|
+
export interface Meta {
|
|
958
|
+
readonly token: string
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
export interface Download {
|
|
962
|
+
readonly data: Uint8Array
|
|
963
|
+
readonly name: string
|
|
964
|
+
readonly type: string
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Exceptions
|
|
968
|
+
|
|
969
|
+
export class UnauthorizedError extends Error {
|
|
970
|
+
name: string = "UnauthorizedError"
|
|
971
|
+
constructor(public message: string = "Unauthorized") {
|
|
972
|
+
super(message)
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
export class InfoError extends Error {
|
|
977
|
+
name: string = "InfoError"
|
|
978
|
+
constructor(public message: string) {
|
|
979
|
+
super(message)
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
export class NotFoundError extends Error {
|
|
984
|
+
name: string = "NotFoundError"
|
|
985
|
+
constructor(public message: string) {
|
|
986
|
+
super(message)
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
export class InputError extends Error {
|
|
991
|
+
name: string = "InputError"
|
|
992
|
+
constructor(public message: string) {
|
|
993
|
+
super(message)
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
export class ProtocolError extends Error {
|
|
998
|
+
name: string = "ProtocolError"
|
|
999
|
+
constructor(public message: string) {
|
|
1000
|
+
super(message)
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
type CacheEntry = {
|
|
1005
|
+
output: any
|
|
1006
|
+
ofiles: any
|
|
1007
|
+
epoch: number
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/**
|
|
1011
|
+
*
|
|
1012
|
+
* JutgeApiClient
|
|
1013
|
+
*
|
|
1014
|
+
*/
|
|
1015
|
+
export class JutgeApiClient {
|
|
1016
|
+
//
|
|
1017
|
+
|
|
1018
|
+
/** Client TTL values (in seconds) */
|
|
1019
|
+
clientTTLs: Map<string, number> = new Map()
|
|
1020
|
+
|
|
1021
|
+
/** Whether to use cache or not */
|
|
1022
|
+
useCache: boolean = true
|
|
1023
|
+
|
|
1024
|
+
/** Whether to log cache or not */
|
|
1025
|
+
logCache: boolean = false
|
|
1026
|
+
|
|
1027
|
+
/** The cache */
|
|
1028
|
+
private cache: Map<string, CacheEntry> = new Map()
|
|
1029
|
+
|
|
1030
|
+
/** URL to talk with the API */
|
|
1031
|
+
JUTGE_API_URL = process.env.JUTGE_API_URL || "https://api.jutge.org/api"
|
|
1032
|
+
|
|
1033
|
+
/** Headers to include in the API requests */
|
|
1034
|
+
headers: Record<string, string> = {}
|
|
1035
|
+
|
|
1036
|
+
/** Meta information */
|
|
1037
|
+
meta: Meta | null = null
|
|
1038
|
+
|
|
1039
|
+
/** Function that sends a request to the API and returns the response. **/
|
|
1040
|
+
async execute(func: string, input: any, ifiles: File[] = []): Promise<[any, Download[]]> {
|
|
1041
|
+
//
|
|
1042
|
+
|
|
1043
|
+
const caching = this.useCache && this.clientTTLs.has(func) && ifiles.length === 0
|
|
1044
|
+
|
|
1045
|
+
// check cache
|
|
1046
|
+
if (caching) {
|
|
1047
|
+
const key = JSON.stringify({ func, input })
|
|
1048
|
+
const entry = this.cache.get(key)
|
|
1049
|
+
if (entry !== undefined) {
|
|
1050
|
+
if (this.logCache) console.log("found")
|
|
1051
|
+
const ttl = this.clientTTLs.get(func)!
|
|
1052
|
+
if (entry.epoch + ttl * 1000 > new Date().valueOf()) {
|
|
1053
|
+
if (this.logCache) console.log("used")
|
|
1054
|
+
return [entry.output, entry.ofiles]
|
|
1055
|
+
} else {
|
|
1056
|
+
if (this.logCache) console.log("expired")
|
|
1057
|
+
this.cache.delete(key)
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
if (this.logCache) console.log("fetch")
|
|
1062
|
+
|
|
1063
|
+
// prepare form
|
|
1064
|
+
const iform = new FormData()
|
|
1065
|
+
const idata = { func, input, meta: this.meta }
|
|
1066
|
+
iform.append("data", JSON.stringify(idata))
|
|
1067
|
+
for (const index in ifiles) iform.append(`file_${index}`, ifiles[index])
|
|
1068
|
+
|
|
1069
|
+
// send request
|
|
1070
|
+
const response = await fetch(this.JUTGE_API_URL, {
|
|
1071
|
+
method: "POST",
|
|
1072
|
+
body: iform,
|
|
1073
|
+
headers: this.headers,
|
|
1074
|
+
})
|
|
1075
|
+
|
|
1076
|
+
// process response
|
|
1077
|
+
const contentType = response.headers.get("content-type")?.split(";")[0].toLowerCase()
|
|
1078
|
+
if (contentType !== "multipart/form-data") {
|
|
1079
|
+
throw new ProtocolError("The content type is not multipart/form-data")
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
const oform = await response.formData()
|
|
1083
|
+
const odata = oform.get("data")
|
|
1084
|
+
const { output, error, duration, operation_id, time } = JSON.parse(odata as string)
|
|
1085
|
+
|
|
1086
|
+
if (error) {
|
|
1087
|
+
this.throwError(error, operation_id)
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// extract ofiles
|
|
1091
|
+
const ofiles = []
|
|
1092
|
+
for (const key of oform.keys()) {
|
|
1093
|
+
const value = oform.get(key)
|
|
1094
|
+
if (value instanceof File) {
|
|
1095
|
+
ofiles.push({
|
|
1096
|
+
data: new Uint8Array(await value.arrayBuffer()),
|
|
1097
|
+
name: value.name,
|
|
1098
|
+
type: value.type,
|
|
1099
|
+
})
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// update cache
|
|
1104
|
+
if (caching) {
|
|
1105
|
+
if (this.logCache) console.log("saved")
|
|
1106
|
+
const key = JSON.stringify({ func, input })
|
|
1107
|
+
this.cache.set(key, { output, ofiles, epoch: new Date().valueOf() })
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
return [output, ofiles]
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/** Function that throws the exception received through the API */
|
|
1114
|
+
throwError(error: Record<string, any>, operation_id: string | undefined) {
|
|
1115
|
+
const message = error.message || "Unknown error"
|
|
1116
|
+
if (error.name === "UnauthorizedError") {
|
|
1117
|
+
throw new UnauthorizedError(message)
|
|
1118
|
+
} else if (error.name === "InfoError") {
|
|
1119
|
+
throw new InfoError(message)
|
|
1120
|
+
} else if (error.name === "NotFoundError") {
|
|
1121
|
+
throw new NotFoundError(message)
|
|
1122
|
+
} else if (error.name === "InputError") {
|
|
1123
|
+
throw new InputError(message)
|
|
1124
|
+
} else {
|
|
1125
|
+
throw new Error(message)
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/** Simple login setting meta */
|
|
1130
|
+
|
|
1131
|
+
async login({ email, password }: { email: string; password: string }): Promise<CredentialsOut> {
|
|
1132
|
+
const [credentials, _] = await this.execute("auth.login", { email, password })
|
|
1133
|
+
if (credentials.error) throw new UnauthorizedError(credentials.error)
|
|
1134
|
+
this.meta = { token: credentials.token }
|
|
1135
|
+
return credentials
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/** Simple login to exam setting meta */
|
|
1139
|
+
async loginExam({
|
|
1140
|
+
email,
|
|
1141
|
+
password,
|
|
1142
|
+
exam,
|
|
1143
|
+
exam_password,
|
|
1144
|
+
}: {
|
|
1145
|
+
email: string
|
|
1146
|
+
password: string
|
|
1147
|
+
exam: string
|
|
1148
|
+
exam_password: string
|
|
1149
|
+
}): Promise<CredentialsOut> {
|
|
1150
|
+
const [credentials, _] = await this.execute("auth.loginExam", { email, password, exam, exam_password })
|
|
1151
|
+
if (credentials.error) throw new UnauthorizedError(credentials.error)
|
|
1152
|
+
this.meta = { token: credentials.token }
|
|
1153
|
+
return credentials
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/** Simple logout */
|
|
1157
|
+
async logout(): Promise<void> {
|
|
1158
|
+
await this.execute("auth.logout", null)
|
|
1159
|
+
this.meta = null
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/** Clear the contents of the cache */
|
|
1163
|
+
clearCache() {
|
|
1164
|
+
if (this.logCache) console.log("clear")
|
|
1165
|
+
this.cache = new Map()
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
/** Provide a new value to the cache */
|
|
1169
|
+
setCache(newCache: string) {
|
|
1170
|
+
const obj = JSON.parse(newCache)
|
|
1171
|
+
this.cache = new Map(Object.entries(obj))
|
|
1172
|
+
this.removeExpired()
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/** Get current value of the cache */
|
|
1176
|
+
getCache(): string {
|
|
1177
|
+
this.removeExpired()
|
|
1178
|
+
const obj = Object.fromEntries(this.cache.entries())
|
|
1179
|
+
return JSON.stringify(obj)
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/** Remove expired entries from cache */
|
|
1183
|
+
private removeExpired() {
|
|
1184
|
+
for (const [key, entry] of this.cache) {
|
|
1185
|
+
const { func } = JSON.parse(key)
|
|
1186
|
+
const ttl = this.clientTTLs.get(func)
|
|
1187
|
+
if (ttl !== undefined && entry.epoch + ttl * 1000 < new Date().getTime()) {
|
|
1188
|
+
this.cache.delete(key)
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
readonly clients: Module_clients
|
|
1194
|
+
readonly auth: Module_auth
|
|
1195
|
+
readonly misc: Module_misc
|
|
1196
|
+
readonly tables: Module_tables
|
|
1197
|
+
readonly problems: Module_problems
|
|
1198
|
+
readonly student: Module_student
|
|
1199
|
+
readonly instructor: Module_instructor
|
|
1200
|
+
readonly admin: Module_admin
|
|
1201
|
+
readonly testing: Module_testing
|
|
1202
|
+
|
|
1203
|
+
constructor() {
|
|
1204
|
+
this.clients = new Module_clients(this)
|
|
1205
|
+
this.auth = new Module_auth(this)
|
|
1206
|
+
this.misc = new Module_misc(this)
|
|
1207
|
+
this.tables = new Module_tables(this)
|
|
1208
|
+
this.problems = new Module_problems(this)
|
|
1209
|
+
this.student = new Module_student(this)
|
|
1210
|
+
this.instructor = new Module_instructor(this)
|
|
1211
|
+
this.admin = new Module_admin(this)
|
|
1212
|
+
this.testing = new Module_testing(this)
|
|
1213
|
+
|
|
1214
|
+
this.clientTTLs.set("misc.getAvatarPacks", 3600)
|
|
1215
|
+
this.clientTTLs.set("misc.getExamIcons", 3600)
|
|
1216
|
+
this.clientTTLs.set("misc.getDemosForCompiler", 3600)
|
|
1217
|
+
this.clientTTLs.set("tables.get", 300)
|
|
1218
|
+
this.clientTTLs.set("tables.getLanguages", 300)
|
|
1219
|
+
this.clientTTLs.set("tables.getCountries", 300)
|
|
1220
|
+
this.clientTTLs.set("tables.getCompilers", 300)
|
|
1221
|
+
this.clientTTLs.set("tables.getDrivers", 300)
|
|
1222
|
+
this.clientTTLs.set("tables.getVerdicts", 300)
|
|
1223
|
+
this.clientTTLs.set("tables.getProglangs", 300)
|
|
1224
|
+
this.clientTTLs.set("problems.getAllAbstractProblems", 3600)
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
*
|
|
1230
|
+
* Module to download clients.
|
|
1231
|
+
*
|
|
1232
|
+
*/
|
|
1233
|
+
class Module_clients {
|
|
1234
|
+
private readonly root: JutgeApiClient
|
|
1235
|
+
|
|
1236
|
+
constructor(root: JutgeApiClient) {
|
|
1237
|
+
this.root = root
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Get Python client.
|
|
1242
|
+
*
|
|
1243
|
+
* 🔐 Authentication: any
|
|
1244
|
+
* No warnings
|
|
1245
|
+
*
|
|
1246
|
+
*/
|
|
1247
|
+
async python(): Promise<Download> {
|
|
1248
|
+
const [output, ofiles] = await this.root.execute("clients.python", null)
|
|
1249
|
+
return ofiles[0]
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* Get TypeScript client.
|
|
1254
|
+
*
|
|
1255
|
+
* 🔐 Authentication: any
|
|
1256
|
+
* No warnings
|
|
1257
|
+
*
|
|
1258
|
+
*/
|
|
1259
|
+
async typescript(): Promise<Download> {
|
|
1260
|
+
const [output, ofiles] = await this.root.execute("clients.typescript", null)
|
|
1261
|
+
return ofiles[0]
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Get JavaScript client.
|
|
1266
|
+
*
|
|
1267
|
+
* 🔐 Authentication: any
|
|
1268
|
+
* No warnings
|
|
1269
|
+
*
|
|
1270
|
+
*/
|
|
1271
|
+
async javascript(): Promise<Download> {
|
|
1272
|
+
const [output, ofiles] = await this.root.execute("clients.javascript", null)
|
|
1273
|
+
return ofiles[0]
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* Get Java client.
|
|
1278
|
+
*
|
|
1279
|
+
* 🔐 Authentication: any
|
|
1280
|
+
* No warnings
|
|
1281
|
+
*
|
|
1282
|
+
*/
|
|
1283
|
+
async java(): Promise<Download> {
|
|
1284
|
+
const [output, ofiles] = await this.root.execute("clients.java", null)
|
|
1285
|
+
return ofiles[0]
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Get Cpp client.
|
|
1290
|
+
*
|
|
1291
|
+
* 🔐 Authentication: any
|
|
1292
|
+
* No warnings
|
|
1293
|
+
*
|
|
1294
|
+
*/
|
|
1295
|
+
async cpp(): Promise<Download> {
|
|
1296
|
+
const [output, ofiles] = await this.root.execute("clients.cpp", null)
|
|
1297
|
+
return ofiles[0]
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Get PHP client.
|
|
1302
|
+
*
|
|
1303
|
+
* 🔐 Authentication: any
|
|
1304
|
+
* No warnings
|
|
1305
|
+
*
|
|
1306
|
+
*/
|
|
1307
|
+
async php(): Promise<Download> {
|
|
1308
|
+
const [output, ofiles] = await this.root.execute("clients.php", null)
|
|
1309
|
+
return ofiles[0]
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
*
|
|
1315
|
+
* Module to provide authentication functions.
|
|
1316
|
+
*
|
|
1317
|
+
*/
|
|
1318
|
+
class Module_auth {
|
|
1319
|
+
private readonly root: JutgeApiClient
|
|
1320
|
+
|
|
1321
|
+
constructor(root: JutgeApiClient) {
|
|
1322
|
+
this.root = root
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* Login: Get an access token.
|
|
1327
|
+
*
|
|
1328
|
+
* 🔐 Authentication: any
|
|
1329
|
+
* No warnings
|
|
1330
|
+
* On success, token is a valid token and error is empty. On failure, token is empty and error is a message.
|
|
1331
|
+
*/
|
|
1332
|
+
async login(data: CredentialsIn): Promise<CredentialsOut> {
|
|
1333
|
+
const [output, ofiles] = await this.root.execute("auth.login", data)
|
|
1334
|
+
return output
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* Logout: Discard the access token.
|
|
1339
|
+
*
|
|
1340
|
+
* 🔐 Authentication: user
|
|
1341
|
+
* No warnings
|
|
1342
|
+
*
|
|
1343
|
+
*/
|
|
1344
|
+
async logout(): Promise<void> {
|
|
1345
|
+
const [output, ofiles] = await this.root.execute("auth.logout", null)
|
|
1346
|
+
return output
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* Login to an exam: Get an access token for an exam.
|
|
1351
|
+
*
|
|
1352
|
+
* 🔐 Authentication: any
|
|
1353
|
+
* No warnings
|
|
1354
|
+
* On success, token is a valid token and error is empty. On failure, token is empty and error is a message.
|
|
1355
|
+
*/
|
|
1356
|
+
async loginExam(data: ExamCredentialsIn): Promise<CredentialsOut> {
|
|
1357
|
+
const [output, ofiles] = await this.root.execute("auth.loginExam", data)
|
|
1358
|
+
return output
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
/**
|
|
1363
|
+
*
|
|
1364
|
+
* Module with miscellaneous endpoints
|
|
1365
|
+
*
|
|
1366
|
+
*/
|
|
1367
|
+
class Module_misc {
|
|
1368
|
+
private readonly root: JutgeApiClient
|
|
1369
|
+
|
|
1370
|
+
constructor(root: JutgeApiClient) {
|
|
1371
|
+
this.root = root
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* Get version information of the API.
|
|
1376
|
+
*
|
|
1377
|
+
* 🔐 Authentication: any
|
|
1378
|
+
* No warnings
|
|
1379
|
+
*
|
|
1380
|
+
*/
|
|
1381
|
+
async getApiVersion(): Promise<ApiVersion> {
|
|
1382
|
+
const [output, ofiles] = await this.root.execute("misc.getApiVersion", null)
|
|
1383
|
+
return output
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
/**
|
|
1387
|
+
* Get requestion information.
|
|
1388
|
+
*
|
|
1389
|
+
* 🔐 Authentication: any
|
|
1390
|
+
* No warnings
|
|
1391
|
+
*
|
|
1392
|
+
*/
|
|
1393
|
+
async getRequestInformation(): Promise<RequestInformation> {
|
|
1394
|
+
const [output, ofiles] = await this.root.execute("misc.getRequestInformation", null)
|
|
1395
|
+
return output
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
/**
|
|
1399
|
+
* Get a fortune message.
|
|
1400
|
+
*
|
|
1401
|
+
* 🔐 Authentication: any
|
|
1402
|
+
* No warnings
|
|
1403
|
+
*
|
|
1404
|
+
*/
|
|
1405
|
+
async getFortune(): Promise<string> {
|
|
1406
|
+
const [output, ofiles] = await this.root.execute("misc.getFortune", null)
|
|
1407
|
+
return output
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Get server time.
|
|
1412
|
+
*
|
|
1413
|
+
* 🔐 Authentication: any
|
|
1414
|
+
* No warnings
|
|
1415
|
+
*
|
|
1416
|
+
*/
|
|
1417
|
+
async getTime(): Promise<Time> {
|
|
1418
|
+
const [output, ofiles] = await this.root.execute("misc.getTime", null)
|
|
1419
|
+
return output
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Get homepage stats.
|
|
1424
|
+
*
|
|
1425
|
+
* 🔐 Authentication: any
|
|
1426
|
+
* No warnings
|
|
1427
|
+
*
|
|
1428
|
+
*/
|
|
1429
|
+
async getHomepageStats(): Promise<HomepageStats> {
|
|
1430
|
+
const [output, ofiles] = await this.root.execute("misc.getHomepageStats", null)
|
|
1431
|
+
return output
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* Get Jutge.org logo as a PNG file.
|
|
1436
|
+
*
|
|
1437
|
+
* 🔐 Authentication: any
|
|
1438
|
+
* No warnings
|
|
1439
|
+
*
|
|
1440
|
+
*/
|
|
1441
|
+
async getLogo(): Promise<Download> {
|
|
1442
|
+
const [output, ofiles] = await this.root.execute("misc.getLogo", null)
|
|
1443
|
+
return ofiles[0]
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
/**
|
|
1447
|
+
* Returns all packs of avatars.
|
|
1448
|
+
*
|
|
1449
|
+
* 🔐 Authentication: any
|
|
1450
|
+
* No warnings
|
|
1451
|
+
* Avatars are used in exams and contests to identify students or participants.
|
|
1452
|
+
*/
|
|
1453
|
+
async getAvatarPacks(): Promise<string[]> {
|
|
1454
|
+
const [output, ofiles] = await this.root.execute("misc.getAvatarPacks", null)
|
|
1455
|
+
return output
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
/**
|
|
1459
|
+
* Returns all exam icons.
|
|
1460
|
+
*
|
|
1461
|
+
* 🔐 Authentication: any
|
|
1462
|
+
* No warnings
|
|
1463
|
+
* Exam icon are used in exams and contests to identify problems.
|
|
1464
|
+
*/
|
|
1465
|
+
async getExamIcons(): Promise<TagsDict> {
|
|
1466
|
+
const [output, ofiles] = await this.root.execute("misc.getExamIcons", null)
|
|
1467
|
+
return output
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
/**
|
|
1471
|
+
* Returns color mappings using colornames notation.
|
|
1472
|
+
*
|
|
1473
|
+
* 🔐 Authentication: any
|
|
1474
|
+
* No warnings
|
|
1475
|
+
* Color mappings may be used to colorize keys in the frontends. Color names are as defined in https://github.com/timoxley/colornames
|
|
1476
|
+
*/
|
|
1477
|
+
async getColors(): Promise<ColorMapping> {
|
|
1478
|
+
const [output, ofiles] = await this.root.execute("misc.getColors", null)
|
|
1479
|
+
return output
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
/**
|
|
1483
|
+
* Returns color mappings using hexadecimal color notation.
|
|
1484
|
+
*
|
|
1485
|
+
* 🔐 Authentication: any
|
|
1486
|
+
* No warnings
|
|
1487
|
+
* Color mappings may be used to colorize keys in the frontends.
|
|
1488
|
+
*/
|
|
1489
|
+
async getHexColors(): Promise<ColorMapping> {
|
|
1490
|
+
const [output, ofiles] = await this.root.execute("misc.getHexColors", null)
|
|
1491
|
+
return output
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/**
|
|
1495
|
+
* Returns code demos for a given compiler as a dictionary of base64 codes indexed by problem_nm.
|
|
1496
|
+
*
|
|
1497
|
+
* 🔐 Authentication: any
|
|
1498
|
+
* No warnings
|
|
1499
|
+
*
|
|
1500
|
+
*/
|
|
1501
|
+
async getDemosForCompiler(compiler_id: string): Promise<Record<string, string>> {
|
|
1502
|
+
const [output, ofiles] = await this.root.execute("misc.getDemosForCompiler", compiler_id)
|
|
1503
|
+
return output
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
/**
|
|
1508
|
+
*
|
|
1509
|
+
* Module with quite static tables
|
|
1510
|
+
*
|
|
1511
|
+
*/
|
|
1512
|
+
class Module_tables {
|
|
1513
|
+
private readonly root: JutgeApiClient
|
|
1514
|
+
|
|
1515
|
+
constructor(root: JutgeApiClient) {
|
|
1516
|
+
this.root = root
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Returns all tables.
|
|
1521
|
+
*
|
|
1522
|
+
* 🔐 Authentication: any
|
|
1523
|
+
* No warnings
|
|
1524
|
+
* Returns all compilers, countries, drivers, languages, proglangs, and verdicts in a single request. This data does not change often, so you should only request it once per session.
|
|
1525
|
+
*/
|
|
1526
|
+
async get(): Promise<AllTables> {
|
|
1527
|
+
const [output, ofiles] = await this.root.execute("tables.get", null)
|
|
1528
|
+
return output
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
/**
|
|
1532
|
+
* Returns all languages.
|
|
1533
|
+
*
|
|
1534
|
+
* 🔐 Authentication: any
|
|
1535
|
+
* No warnings
|
|
1536
|
+
* Returns all languages as a dictionary of objects, indexed by id.
|
|
1537
|
+
*/
|
|
1538
|
+
async getLanguages(): Promise<Record<string, Language>> {
|
|
1539
|
+
const [output, ofiles] = await this.root.execute("tables.getLanguages", null)
|
|
1540
|
+
return output
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
/**
|
|
1544
|
+
* Returns all countries.
|
|
1545
|
+
*
|
|
1546
|
+
* 🔐 Authentication: any
|
|
1547
|
+
* No warnings
|
|
1548
|
+
* Returns all countries as a dictionary of objects, indexed by id.
|
|
1549
|
+
*/
|
|
1550
|
+
async getCountries(): Promise<Record<string, Country>> {
|
|
1551
|
+
const [output, ofiles] = await this.root.execute("tables.getCountries", null)
|
|
1552
|
+
return output
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
/**
|
|
1556
|
+
* Returns all compilers.
|
|
1557
|
+
*
|
|
1558
|
+
* 🔐 Authentication: any
|
|
1559
|
+
* No warnings
|
|
1560
|
+
* Returns all compilers as a dictionary of objects, indexed by id.
|
|
1561
|
+
*/
|
|
1562
|
+
async getCompilers(): Promise<Record<string, Compiler>> {
|
|
1563
|
+
const [output, ofiles] = await this.root.execute("tables.getCompilers", null)
|
|
1564
|
+
return output
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/**
|
|
1568
|
+
* Returns all drivers.
|
|
1569
|
+
*
|
|
1570
|
+
* 🔐 Authentication: any
|
|
1571
|
+
* No warnings
|
|
1572
|
+
* Returns all drivers as a dictionary of objects, indexed by id.
|
|
1573
|
+
*/
|
|
1574
|
+
async getDrivers(): Promise<Record<string, Driver>> {
|
|
1575
|
+
const [output, ofiles] = await this.root.execute("tables.getDrivers", null)
|
|
1576
|
+
return output
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* Returns all verdicts.
|
|
1581
|
+
*
|
|
1582
|
+
* 🔐 Authentication: any
|
|
1583
|
+
* No warnings
|
|
1584
|
+
* Returns all verdicts as a dictionary of objects, indexed by id.
|
|
1585
|
+
*/
|
|
1586
|
+
async getVerdicts(): Promise<Record<string, Verdict>> {
|
|
1587
|
+
const [output, ofiles] = await this.root.execute("tables.getVerdicts", null)
|
|
1588
|
+
return output
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
/**
|
|
1592
|
+
* Returns all proglangs.
|
|
1593
|
+
*
|
|
1594
|
+
* 🔐 Authentication: any
|
|
1595
|
+
* No warnings
|
|
1596
|
+
* Returns all proglangs (porgramming languages) as a dictionary of objects, indexed by id.
|
|
1597
|
+
*/
|
|
1598
|
+
async getProglangs(): Promise<Record<string, Proglang>> {
|
|
1599
|
+
const [output, ofiles] = await this.root.execute("tables.getProglangs", null)
|
|
1600
|
+
return output
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
/**
|
|
1605
|
+
*
|
|
1606
|
+
* Module with endpoints related to problems.
|
|
1607
|
+
|
|
1608
|
+
There are two types of problems: *abstract problems* and *problems*. An abstract
|
|
1609
|
+
problem is a group of problems. A problem is an instance of an abstract problem
|
|
1610
|
+
in a particular language. Abstract problems are identified by a `problem_nm` (such
|
|
1611
|
+
as 'P68688'), while problems are identified by a `problem_id` including its
|
|
1612
|
+
`language_id` (such as 'P68688_en'). Abstract problems have a list of problems,
|
|
1613
|
+
while problems have an abstract problem. Abstract problems have an author, while
|
|
1614
|
+
problems have a translator.
|
|
1615
|
+
|
|
1616
|
+
Available problems depend on the actor issuing the request. For example, non
|
|
1617
|
+
authenticated users can only access public problems, while authenticated
|
|
1618
|
+
users can potentially access more problems.
|
|
1619
|
+
|
|
1620
|
+
*
|
|
1621
|
+
*/
|
|
1622
|
+
class Module_problems {
|
|
1623
|
+
private readonly root: JutgeApiClient
|
|
1624
|
+
|
|
1625
|
+
constructor(root: JutgeApiClient) {
|
|
1626
|
+
this.root = root
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/**
|
|
1630
|
+
* Get all available abstract problems.
|
|
1631
|
+
*
|
|
1632
|
+
* 🔐 Authentication: any
|
|
1633
|
+
* No warnings
|
|
1634
|
+
* Includes problems.
|
|
1635
|
+
*/
|
|
1636
|
+
async getAllAbstractProblems(): Promise<Record<string, AbstractProblem>> {
|
|
1637
|
+
const [output, ofiles] = await this.root.execute("problems.getAllAbstractProblems", null)
|
|
1638
|
+
return output
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
/**
|
|
1642
|
+
* Get available abstract problems whose keys are in `problem_nms`.
|
|
1643
|
+
*
|
|
1644
|
+
* 🔐 Authentication: any
|
|
1645
|
+
* No warnings
|
|
1646
|
+
* Includes problems.
|
|
1647
|
+
*/
|
|
1648
|
+
async getAbstractProblems(problem_nms: string): Promise<Record<string, AbstractProblem>> {
|
|
1649
|
+
const [output, ofiles] = await this.root.execute("problems.getAbstractProblems", problem_nms)
|
|
1650
|
+
return output
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Get available abstract problems that belong to a list.
|
|
1655
|
+
*
|
|
1656
|
+
* 🔐 Authentication: any
|
|
1657
|
+
* No warnings
|
|
1658
|
+
* Includes problems.
|
|
1659
|
+
*/
|
|
1660
|
+
async getAbstractProblemsInList(list_key: string): Promise<Record<string, AbstractProblem>> {
|
|
1661
|
+
const [output, ofiles] = await this.root.execute("problems.getAbstractProblemsInList", list_key)
|
|
1662
|
+
return output
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* Get an abstract problem.
|
|
1667
|
+
*
|
|
1668
|
+
* 🔐 Authentication: any
|
|
1669
|
+
* No warnings
|
|
1670
|
+
* Includes problems
|
|
1671
|
+
*/
|
|
1672
|
+
async getAbstractProblem(problem_nm: string): Promise<AbstractProblem> {
|
|
1673
|
+
const [output, ofiles] = await this.root.execute("problems.getAbstractProblem", problem_nm)
|
|
1674
|
+
return output
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Get supplementary information of an abstract problem.
|
|
1679
|
+
*
|
|
1680
|
+
* 🔐 Authentication: any
|
|
1681
|
+
* No warnings
|
|
1682
|
+
* Includes accepted compilers and accepted proglangs
|
|
1683
|
+
*/
|
|
1684
|
+
async getAbstractProblemSuppl(problem_nm: string): Promise<AbstractProblemSuppl> {
|
|
1685
|
+
const [output, ofiles] = await this.root.execute("problems.getAbstractProblemSuppl", problem_nm)
|
|
1686
|
+
return output
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
/**
|
|
1690
|
+
* Get a problem.
|
|
1691
|
+
*
|
|
1692
|
+
* 🔐 Authentication: any
|
|
1693
|
+
* No warnings
|
|
1694
|
+
* Includes abstract problem.
|
|
1695
|
+
*/
|
|
1696
|
+
async getProblem(problem_id: string): Promise<Problem> {
|
|
1697
|
+
const [output, ofiles] = await this.root.execute("problems.getProblem", problem_id)
|
|
1698
|
+
return output
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
/**
|
|
1702
|
+
* Get a problem with more infos.
|
|
1703
|
+
*
|
|
1704
|
+
* 🔐 Authentication: any
|
|
1705
|
+
* No warnings
|
|
1706
|
+
* Includes abstract problem, which includes statements, testcases, etc.
|
|
1707
|
+
*/
|
|
1708
|
+
async getProblemRich(problem_id: string): Promise<ProblemRich> {
|
|
1709
|
+
const [output, ofiles] = await this.root.execute("problems.getProblemRich", problem_id)
|
|
1710
|
+
return output
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Get supplementary information of a problem.
|
|
1715
|
+
*
|
|
1716
|
+
* 🔐 Authentication: any
|
|
1717
|
+
* No warnings
|
|
1718
|
+
* Includes accepted compilers, accepted proglangs, official solutions
|
|
1719
|
+
checks and handler specifications
|
|
1720
|
+
*/
|
|
1721
|
+
async getProblemSuppl(problem_id: string): Promise<ProblemSuppl> {
|
|
1722
|
+
const [output, ofiles] = await this.root.execute("problems.getProblemSuppl", problem_id)
|
|
1723
|
+
return output
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
/**
|
|
1727
|
+
* Get sample testcases of a problem.
|
|
1728
|
+
*
|
|
1729
|
+
* 🔐 Authentication: any
|
|
1730
|
+
* No warnings
|
|
1731
|
+
*
|
|
1732
|
+
*/
|
|
1733
|
+
async getSampleTestcases(problem_id: string): Promise<Testcase[]> {
|
|
1734
|
+
const [output, ofiles] = await this.root.execute("problems.getSampleTestcases", problem_id)
|
|
1735
|
+
return output
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* Get public testcases of a problem.
|
|
1740
|
+
*
|
|
1741
|
+
* 🔐 Authentication: any
|
|
1742
|
+
* No warnings
|
|
1743
|
+
* Public testcases are like sample testcases, but are not meant to be show
|
|
1744
|
+
in the problem statatement, because of their long length.
|
|
1745
|
+
*/
|
|
1746
|
+
async getPublicTestcases(problem_id: string): Promise<Testcase[]> {
|
|
1747
|
+
const [output, ofiles] = await this.root.execute("problems.getPublicTestcases", problem_id)
|
|
1748
|
+
return output
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
/**
|
|
1752
|
+
* Get Html statement of a problem.
|
|
1753
|
+
*
|
|
1754
|
+
* 🔐 Authentication: any
|
|
1755
|
+
* No warnings
|
|
1756
|
+
* We are working on this, please provide feedback.
|
|
1757
|
+
*/
|
|
1758
|
+
async getHtmlStatement(problem_id: string): Promise<string> {
|
|
1759
|
+
const [output, ofiles] = await this.root.execute("problems.getHtmlStatement", problem_id)
|
|
1760
|
+
return output
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Get Text statement of a problem.
|
|
1765
|
+
*
|
|
1766
|
+
* 🔐 Authentication: any
|
|
1767
|
+
* No warnings
|
|
1768
|
+
*
|
|
1769
|
+
*/
|
|
1770
|
+
async getTextStatement(problem_id: string): Promise<string> {
|
|
1771
|
+
const [output, ofiles] = await this.root.execute("problems.getTextStatement", problem_id)
|
|
1772
|
+
return output
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
/**
|
|
1776
|
+
* Get Markdown statement of a problem.
|
|
1777
|
+
*
|
|
1778
|
+
* 🔐 Authentication: any
|
|
1779
|
+
* No warnings
|
|
1780
|
+
*
|
|
1781
|
+
*/
|
|
1782
|
+
async getMarkdownStatement(problem_id: string): Promise<string> {
|
|
1783
|
+
const [output, ofiles] = await this.root.execute("problems.getMarkdownStatement", problem_id)
|
|
1784
|
+
return output
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
/**
|
|
1788
|
+
* Get PDF statement of a problem.
|
|
1789
|
+
*
|
|
1790
|
+
* 🔐 Authentication: any
|
|
1791
|
+
* No warnings
|
|
1792
|
+
*
|
|
1793
|
+
*/
|
|
1794
|
+
async getPdfStatement(problem_id: string): Promise<Download> {
|
|
1795
|
+
const [output, ofiles] = await this.root.execute("problems.getPdfStatement", problem_id)
|
|
1796
|
+
return ofiles[0]
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
/**
|
|
1800
|
+
* Get ZIP archive of a problem. This includes the PDF statement and sample testcases.
|
|
1801
|
+
*
|
|
1802
|
+
* 🔐 Authentication: any
|
|
1803
|
+
* No warnings
|
|
1804
|
+
*
|
|
1805
|
+
*/
|
|
1806
|
+
async getZipStatement(problem_id: string): Promise<Download> {
|
|
1807
|
+
const [output, ofiles] = await this.root.execute("problems.getZipStatement", problem_id)
|
|
1808
|
+
return ofiles[0]
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
/**
|
|
1812
|
+
* Get list of template files of a problem (`main.*`, `code.*`, `public.tar`, etc.).
|
|
1813
|
+
*
|
|
1814
|
+
* 🔐 Authentication: any
|
|
1815
|
+
* No warnings
|
|
1816
|
+
*
|
|
1817
|
+
*/
|
|
1818
|
+
async getTemplates(problem_id: string): Promise<string[]> {
|
|
1819
|
+
const [output, ofiles] = await this.root.execute("problems.getTemplates", problem_id)
|
|
1820
|
+
return output
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
/**
|
|
1824
|
+
* Get a template file of a problem.
|
|
1825
|
+
*
|
|
1826
|
+
* 🔐 Authentication: any
|
|
1827
|
+
* No warnings
|
|
1828
|
+
*
|
|
1829
|
+
*/
|
|
1830
|
+
async getTemplate(data: { problem_id: string; template: string }): Promise<Download> {
|
|
1831
|
+
const [output, ofiles] = await this.root.execute("problems.getTemplate", data)
|
|
1832
|
+
return ofiles[0]
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
/**
|
|
1836
|
+
* Get results for a semantic search for statement problems. The array is sorted by score (better at the top).
|
|
1837
|
+
*
|
|
1838
|
+
* 🔐 Authentication: any
|
|
1839
|
+
* No warnings
|
|
1840
|
+
*
|
|
1841
|
+
*/
|
|
1842
|
+
async semanticSearch(data: { query: string; limit: number }): Promise<SearchResults> {
|
|
1843
|
+
const [output, ofiles] = await this.root.execute("problems.semanticSearch", data)
|
|
1844
|
+
return output
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
/**
|
|
1848
|
+
* Get results for a full text search for statement problems. The array is sorted by score (better at the top). Queries are matched against titles and statements and can use boolean operators.
|
|
1849
|
+
*
|
|
1850
|
+
* 🔐 Authentication: any
|
|
1851
|
+
* No warnings
|
|
1852
|
+
*
|
|
1853
|
+
*/
|
|
1854
|
+
async fullTextSearch(data: { query: string; limit: number }): Promise<SearchResults> {
|
|
1855
|
+
const [output, ofiles] = await this.root.execute("problems.fullTextSearch", data)
|
|
1856
|
+
return output
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
/**
|
|
1861
|
+
*
|
|
1862
|
+
* These operations are available to all users, provided they are authenticated.
|
|
1863
|
+
*
|
|
1864
|
+
*/
|
|
1865
|
+
class Module_student {
|
|
1866
|
+
private readonly root: JutgeApiClient
|
|
1867
|
+
|
|
1868
|
+
readonly keys: Module_student_keys
|
|
1869
|
+
readonly profile: Module_student_profile
|
|
1870
|
+
readonly dashboard: Module_student_dashboard
|
|
1871
|
+
readonly submissions: Module_student_submissions
|
|
1872
|
+
readonly courses: Module_student_courses
|
|
1873
|
+
readonly lists: Module_student_lists
|
|
1874
|
+
readonly exam: Module_student_exam
|
|
1875
|
+
readonly statuses: Module_student_statuses
|
|
1876
|
+
readonly awards: Module_student_awards
|
|
1877
|
+
|
|
1878
|
+
constructor(root: JutgeApiClient) {
|
|
1879
|
+
this.root = root
|
|
1880
|
+
this.keys = new Module_student_keys(root)
|
|
1881
|
+
this.profile = new Module_student_profile(root)
|
|
1882
|
+
this.dashboard = new Module_student_dashboard(root)
|
|
1883
|
+
this.submissions = new Module_student_submissions(root)
|
|
1884
|
+
this.courses = new Module_student_courses(root)
|
|
1885
|
+
this.lists = new Module_student_lists(root)
|
|
1886
|
+
this.exam = new Module_student_exam(root)
|
|
1887
|
+
this.statuses = new Module_student_statuses(root)
|
|
1888
|
+
this.awards = new Module_student_awards(root)
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
/**
|
|
1893
|
+
*
|
|
1894
|
+
* This module exposes all valid keys for problems, courses and lists that a user can access.
|
|
1895
|
+
*
|
|
1896
|
+
*/
|
|
1897
|
+
class Module_student_keys {
|
|
1898
|
+
private readonly root: JutgeApiClient
|
|
1899
|
+
|
|
1900
|
+
constructor(root: JutgeApiClient) {
|
|
1901
|
+
this.root = root
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* Get problem, courses (as enrolled and available) and list keys.
|
|
1906
|
+
*
|
|
1907
|
+
* 🔐 Authentication: user
|
|
1908
|
+
* No warnings
|
|
1909
|
+
*
|
|
1910
|
+
*/
|
|
1911
|
+
async get(): Promise<AllKeys> {
|
|
1912
|
+
const [output, ofiles] = await this.root.execute("student.keys.get", null)
|
|
1913
|
+
return output
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
/**
|
|
1917
|
+
* Get problem keys.
|
|
1918
|
+
*
|
|
1919
|
+
* 🔐 Authentication: user
|
|
1920
|
+
* No warnings
|
|
1921
|
+
*
|
|
1922
|
+
*/
|
|
1923
|
+
async getProblems(): Promise<string[]> {
|
|
1924
|
+
const [output, ofiles] = await this.root.execute("student.keys.getProblems", null)
|
|
1925
|
+
return output
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
/**
|
|
1929
|
+
* Get enrolled course keys.
|
|
1930
|
+
*
|
|
1931
|
+
* 🔐 Authentication: user
|
|
1932
|
+
* No warnings
|
|
1933
|
+
*
|
|
1934
|
+
*/
|
|
1935
|
+
async getEnrolledCourses(): Promise<string[]> {
|
|
1936
|
+
const [output, ofiles] = await this.root.execute("student.keys.getEnrolledCourses", null)
|
|
1937
|
+
return output
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
/**
|
|
1941
|
+
* Get available course keys.
|
|
1942
|
+
*
|
|
1943
|
+
* 🔐 Authentication: user
|
|
1944
|
+
* No warnings
|
|
1945
|
+
*
|
|
1946
|
+
*/
|
|
1947
|
+
async getAvailableCourses(): Promise<string[]> {
|
|
1948
|
+
const [output, ofiles] = await this.root.execute("student.keys.getAvailableCourses", null)
|
|
1949
|
+
return output
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
/**
|
|
1953
|
+
* Get list keys.
|
|
1954
|
+
*
|
|
1955
|
+
* 🔐 Authentication: user
|
|
1956
|
+
* No warnings
|
|
1957
|
+
*
|
|
1958
|
+
*/
|
|
1959
|
+
async getLists(): Promise<string[]> {
|
|
1960
|
+
const [output, ofiles] = await this.root.execute("student.keys.getLists", null)
|
|
1961
|
+
return output
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
/**
|
|
1966
|
+
*
|
|
1967
|
+
* This module exposes the user profile.
|
|
1968
|
+
*
|
|
1969
|
+
*/
|
|
1970
|
+
class Module_student_profile {
|
|
1971
|
+
private readonly root: JutgeApiClient
|
|
1972
|
+
|
|
1973
|
+
constructor(root: JutgeApiClient) {
|
|
1974
|
+
this.root = root
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* Get the profile.
|
|
1979
|
+
*
|
|
1980
|
+
* 🔐 Authentication: user
|
|
1981
|
+
* No warnings
|
|
1982
|
+
* In case of exams, some fields are not nullified to avoid cheating.
|
|
1983
|
+
*/
|
|
1984
|
+
async get(): Promise<Profile> {
|
|
1985
|
+
const [output, ofiles] = await this.root.execute("student.profile.get", null)
|
|
1986
|
+
return output
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
/**
|
|
1990
|
+
* Returns the avatar as a PNG file.
|
|
1991
|
+
*
|
|
1992
|
+
* 🔐 Authentication: user
|
|
1993
|
+
* No warnings
|
|
1994
|
+
*
|
|
1995
|
+
*/
|
|
1996
|
+
async getAvatar(): Promise<Download> {
|
|
1997
|
+
const [output, ofiles] = await this.root.execute("student.profile.getAvatar", null)
|
|
1998
|
+
return ofiles[0]
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/**
|
|
2002
|
+
* Update the profile
|
|
2003
|
+
*
|
|
2004
|
+
* 🔐 Authentication: user
|
|
2005
|
+
* No warnings
|
|
2006
|
+
*
|
|
2007
|
+
*/
|
|
2008
|
+
async update(data: NewProfile): Promise<void> {
|
|
2009
|
+
const [output, ofiles] = await this.root.execute("student.profile.update", data)
|
|
2010
|
+
return output
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
/**
|
|
2014
|
+
* Update the avatar with new PNG.
|
|
2015
|
+
*
|
|
2016
|
+
* 🔐 Authentication: user
|
|
2017
|
+
* No warnings
|
|
2018
|
+
*
|
|
2019
|
+
*/
|
|
2020
|
+
async updateAvatar(ifile: File): Promise<void> {
|
|
2021
|
+
const [output, ofiles] = await this.root.execute("student.profile.updateAvatar", null, [ifile])
|
|
2022
|
+
return output
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/**
|
|
2026
|
+
* Update password.
|
|
2027
|
+
*
|
|
2028
|
+
* 🔐 Authentication: user
|
|
2029
|
+
* No warnings
|
|
2030
|
+
* Receives the old password and the new one, and changes the password if the old one is correct and the new one strong enough.
|
|
2031
|
+
*/
|
|
2032
|
+
async updatePassword(data: NewPassword): Promise<void> {
|
|
2033
|
+
const [output, ofiles] = await this.root.execute("student.profile.updatePassword", data)
|
|
2034
|
+
return output
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
/**
|
|
2039
|
+
*
|
|
2040
|
+
* No description yet
|
|
2041
|
+
*
|
|
2042
|
+
*/
|
|
2043
|
+
class Module_student_dashboard {
|
|
2044
|
+
private readonly root: JutgeApiClient
|
|
2045
|
+
|
|
2046
|
+
constructor(root: JutgeApiClient) {
|
|
2047
|
+
this.root = root
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
/**
|
|
2051
|
+
* Get the ranking of the user over all users in the system.
|
|
2052
|
+
*
|
|
2053
|
+
* 🔐 Authentication: user
|
|
2054
|
+
* No warnings
|
|
2055
|
+
*
|
|
2056
|
+
*/
|
|
2057
|
+
async getAbsoluteRanking(): Promise<number> {
|
|
2058
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getAbsoluteRanking", null)
|
|
2059
|
+
return output
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
/**
|
|
2063
|
+
* Get all distributions.
|
|
2064
|
+
*
|
|
2065
|
+
* 🔐 Authentication: user
|
|
2066
|
+
* No warnings
|
|
2067
|
+
*
|
|
2068
|
+
*/
|
|
2069
|
+
async getAllDistributions(): Promise<AllDistributions> {
|
|
2070
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getAllDistributions", null)
|
|
2071
|
+
return output
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
/**
|
|
2075
|
+
* Get compilers distribution.
|
|
2076
|
+
*
|
|
2077
|
+
* 🔐 Authentication: user
|
|
2078
|
+
* No warnings
|
|
2079
|
+
*
|
|
2080
|
+
*/
|
|
2081
|
+
async getCompilersDistribution(): Promise<Distribution> {
|
|
2082
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getCompilersDistribution", null)
|
|
2083
|
+
return output
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* Get dashboard.
|
|
2088
|
+
*
|
|
2089
|
+
* 🔐 Authentication: user
|
|
2090
|
+
* No warnings
|
|
2091
|
+
*
|
|
2092
|
+
*/
|
|
2093
|
+
async getDashboard(): Promise<Dashboard> {
|
|
2094
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getDashboard", null)
|
|
2095
|
+
return output
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
/**
|
|
2099
|
+
* Get heatmap calendar of submissions.
|
|
2100
|
+
*
|
|
2101
|
+
* 🔐 Authentication: user
|
|
2102
|
+
* No warnings
|
|
2103
|
+
*
|
|
2104
|
+
*/
|
|
2105
|
+
async getHeatmapCalendar(): Promise<HeatmapCalendar> {
|
|
2106
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getHeatmapCalendar", null)
|
|
2107
|
+
return output
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
/**
|
|
2111
|
+
* Get programming languages distribution.
|
|
2112
|
+
*
|
|
2113
|
+
* 🔐 Authentication: user
|
|
2114
|
+
* No warnings
|
|
2115
|
+
*
|
|
2116
|
+
*/
|
|
2117
|
+
async getProglangsDistribution(): Promise<Distribution> {
|
|
2118
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getProglangsDistribution", null)
|
|
2119
|
+
return output
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
/**
|
|
2123
|
+
* Get dashboard stats.
|
|
2124
|
+
*
|
|
2125
|
+
* 🔐 Authentication: user
|
|
2126
|
+
* No warnings
|
|
2127
|
+
*
|
|
2128
|
+
*/
|
|
2129
|
+
async getStats(): Promise<Distribution> {
|
|
2130
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getStats", null)
|
|
2131
|
+
return output
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
/**
|
|
2135
|
+
* Get fancy Jutge level.
|
|
2136
|
+
*
|
|
2137
|
+
* 🔐 Authentication: user
|
|
2138
|
+
* No warnings
|
|
2139
|
+
*
|
|
2140
|
+
*/
|
|
2141
|
+
async getLevel(): Promise<string> {
|
|
2142
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getLevel", null)
|
|
2143
|
+
return output
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
/**
|
|
2147
|
+
* Get submissions by hour distribution.
|
|
2148
|
+
*
|
|
2149
|
+
* 🔐 Authentication: user
|
|
2150
|
+
* No warnings
|
|
2151
|
+
*
|
|
2152
|
+
*/
|
|
2153
|
+
async getSubmissionsByHour(): Promise<Distribution> {
|
|
2154
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getSubmissionsByHour", null)
|
|
2155
|
+
return output
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
/**
|
|
2159
|
+
* Get submissions by weekday distribution.
|
|
2160
|
+
*
|
|
2161
|
+
* 🔐 Authentication: user
|
|
2162
|
+
* No warnings
|
|
2163
|
+
*
|
|
2164
|
+
*/
|
|
2165
|
+
async getSubmissionsByWeekDay(): Promise<Distribution> {
|
|
2166
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getSubmissionsByWeekDay", null)
|
|
2167
|
+
return output
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
/**
|
|
2171
|
+
* Get verdicts distribution.
|
|
2172
|
+
*
|
|
2173
|
+
* 🔐 Authentication: user
|
|
2174
|
+
* No warnings
|
|
2175
|
+
*
|
|
2176
|
+
*/
|
|
2177
|
+
async getVerdictsDistribution(): Promise<Distribution> {
|
|
2178
|
+
const [output, ofiles] = await this.root.execute("student.dashboard.getVerdictsDistribution", null)
|
|
2179
|
+
return output
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
/**
|
|
2184
|
+
*
|
|
2185
|
+
* No description yet
|
|
2186
|
+
*
|
|
2187
|
+
*/
|
|
2188
|
+
class Module_student_submissions {
|
|
2189
|
+
private readonly root: JutgeApiClient
|
|
2190
|
+
|
|
2191
|
+
constructor(root: JutgeApiClient) {
|
|
2192
|
+
this.root = root
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
/**
|
|
2196
|
+
* Get index of all submissions for an abstract problem.
|
|
2197
|
+
*
|
|
2198
|
+
* 🔐 Authentication: user
|
|
2199
|
+
* No warnings
|
|
2200
|
+
* Grouped by problem.
|
|
2201
|
+
*/
|
|
2202
|
+
async indexForAbstractProblem(problem_nm: string): Promise<Record<string, Record<string, Submission>>> {
|
|
2203
|
+
const [output, ofiles] = await this.root.execute("student.submissions.indexForAbstractProblem", problem_nm)
|
|
2204
|
+
return output
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
/**
|
|
2208
|
+
* Get index of all submissions for a problem.
|
|
2209
|
+
*
|
|
2210
|
+
* 🔐 Authentication: user
|
|
2211
|
+
* No warnings
|
|
2212
|
+
*
|
|
2213
|
+
*/
|
|
2214
|
+
async indexForProblem(problem_id: string): Promise<Record<string, Submission>> {
|
|
2215
|
+
const [output, ofiles] = await this.root.execute("student.submissions.indexForProblem", problem_id)
|
|
2216
|
+
return output
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
/**
|
|
2220
|
+
* Get all submissions.
|
|
2221
|
+
*
|
|
2222
|
+
* 🔐 Authentication: user
|
|
2223
|
+
* No warnings
|
|
2224
|
+
* Flat array of submissions in chronological order.
|
|
2225
|
+
*/
|
|
2226
|
+
async getAll(): Promise<Submission[]> {
|
|
2227
|
+
const [output, ofiles] = await this.root.execute("student.submissions.getAll", null)
|
|
2228
|
+
return output
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
/**
|
|
2232
|
+
* Submit a solution to the Judge, easy interface.
|
|
2233
|
+
*
|
|
2234
|
+
* 🔐 Authentication: user
|
|
2235
|
+
* No warnings
|
|
2236
|
+
*
|
|
2237
|
+
*/
|
|
2238
|
+
async submit(data: { problem_id: string; compiler_id: string; code: string; annotation: string }): Promise<string> {
|
|
2239
|
+
const [output, ofiles] = await this.root.execute("student.submissions.submit", data)
|
|
2240
|
+
return output
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
/**
|
|
2244
|
+
* Submit a solution to the Judge, full interface.
|
|
2245
|
+
*
|
|
2246
|
+
* 🔐 Authentication: user
|
|
2247
|
+
* No warnings
|
|
2248
|
+
*
|
|
2249
|
+
*/
|
|
2250
|
+
async submitFull(data: NewSubmissionIn, ifile: File): Promise<NewSubmissionOut> {
|
|
2251
|
+
const [output, ofiles] = await this.root.execute("student.submissions.submitFull", data, [ifile])
|
|
2252
|
+
return output
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
/**
|
|
2256
|
+
* Get a submission.
|
|
2257
|
+
*
|
|
2258
|
+
* 🔐 Authentication: user
|
|
2259
|
+
* No warnings
|
|
2260
|
+
*
|
|
2261
|
+
*/
|
|
2262
|
+
async get(data: { problem_id: string; submission_id: string }): Promise<Submission> {
|
|
2263
|
+
const [output, ofiles] = await this.root.execute("student.submissions.get", data)
|
|
2264
|
+
return output
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
/**
|
|
2268
|
+
* Get code for a submission as a string in base64.
|
|
2269
|
+
*
|
|
2270
|
+
* 🔐 Authentication: user
|
|
2271
|
+
* No warnings
|
|
2272
|
+
*
|
|
2273
|
+
*/
|
|
2274
|
+
async getCodeAsB64(data: { problem_id: string; submission_id: string }): Promise<string> {
|
|
2275
|
+
const [output, ofiles] = await this.root.execute("student.submissions.getCodeAsB64", data)
|
|
2276
|
+
return output
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
/**
|
|
2280
|
+
* Get code metrics for a submission as JSON.
|
|
2281
|
+
*
|
|
2282
|
+
* 🔐 Authentication: user
|
|
2283
|
+
* ❌ Warning: TODO: add more documentation
|
|
2284
|
+
* See https://github.com/jutge-org/jutge-code-metrics for details.
|
|
2285
|
+
*/
|
|
2286
|
+
async getCodeMetrics(data: { problem_id: string; submission_id: string }): Promise<any> {
|
|
2287
|
+
const [output, ofiles] = await this.root.execute("student.submissions.getCodeMetrics", data)
|
|
2288
|
+
return output
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
/**
|
|
2292
|
+
* Get list of awards ids for a submission.
|
|
2293
|
+
*
|
|
2294
|
+
* 🔐 Authentication: user
|
|
2295
|
+
* No warnings
|
|
2296
|
+
*
|
|
2297
|
+
*/
|
|
2298
|
+
async getAwards(data: { problem_id: string; submission_id: string }): Promise<string[]> {
|
|
2299
|
+
const [output, ofiles] = await this.root.execute("student.submissions.getAwards", data)
|
|
2300
|
+
return output
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
/**
|
|
2304
|
+
* Get analysis of a submission.
|
|
2305
|
+
*
|
|
2306
|
+
* 🔐 Authentication: user
|
|
2307
|
+
* No warnings
|
|
2308
|
+
*
|
|
2309
|
+
*/
|
|
2310
|
+
async getAnalysis(data: { problem_id: string; submission_id: string }): Promise<SubmissionAnalysis[]> {
|
|
2311
|
+
const [output, ofiles] = await this.root.execute("student.submissions.getAnalysis", data)
|
|
2312
|
+
return output
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
/**
|
|
2316
|
+
* Get a (public) testcase analysis of a submission.
|
|
2317
|
+
*
|
|
2318
|
+
* 🔐 Authentication: user
|
|
2319
|
+
* No warnings
|
|
2320
|
+
*
|
|
2321
|
+
*/
|
|
2322
|
+
async getTestcaseAnalysis(data: {
|
|
2323
|
+
problem_id: string
|
|
2324
|
+
submission_id: string
|
|
2325
|
+
testcase: string
|
|
2326
|
+
}): Promise<TestcaseAnalysis> {
|
|
2327
|
+
const [output, ofiles] = await this.root.execute("student.submissions.getTestcaseAnalysis", data)
|
|
2328
|
+
return output
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
/**
|
|
2333
|
+
*
|
|
2334
|
+
* No description yet
|
|
2335
|
+
*
|
|
2336
|
+
*/
|
|
2337
|
+
class Module_student_courses {
|
|
2338
|
+
private readonly root: JutgeApiClient
|
|
2339
|
+
|
|
2340
|
+
constructor(root: JutgeApiClient) {
|
|
2341
|
+
this.root = root
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
/**
|
|
2345
|
+
* Get index of all available courses.
|
|
2346
|
+
*
|
|
2347
|
+
* 🔐 Authentication: user
|
|
2348
|
+
* No warnings
|
|
2349
|
+
*
|
|
2350
|
+
*/
|
|
2351
|
+
async indexAvailable(): Promise<Record<string, BriefCourse>> {
|
|
2352
|
+
const [output, ofiles] = await this.root.execute("student.courses.indexAvailable", null)
|
|
2353
|
+
return output
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
/**
|
|
2357
|
+
* Get index of all enrolled courses.
|
|
2358
|
+
*
|
|
2359
|
+
* 🔐 Authentication: user
|
|
2360
|
+
* No warnings
|
|
2361
|
+
*
|
|
2362
|
+
*/
|
|
2363
|
+
async indexEnrolled(): Promise<Record<string, BriefCourse>> {
|
|
2364
|
+
const [output, ofiles] = await this.root.execute("student.courses.indexEnrolled", null)
|
|
2365
|
+
return output
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
/**
|
|
2369
|
+
* Get an available course.
|
|
2370
|
+
*
|
|
2371
|
+
* 🔐 Authentication: user
|
|
2372
|
+
* No warnings
|
|
2373
|
+
* Includes owner and lists.
|
|
2374
|
+
*/
|
|
2375
|
+
async getAvailable(course_key: string): Promise<Course> {
|
|
2376
|
+
const [output, ofiles] = await this.root.execute("student.courses.getAvailable", course_key)
|
|
2377
|
+
return output
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
/**
|
|
2381
|
+
* Get an enrolled course.
|
|
2382
|
+
*
|
|
2383
|
+
* 🔐 Authentication: user
|
|
2384
|
+
* No warnings
|
|
2385
|
+
* Includes owner and lists.
|
|
2386
|
+
*/
|
|
2387
|
+
async getEnrolled(course_key: string): Promise<Course> {
|
|
2388
|
+
const [output, ofiles] = await this.root.execute("student.courses.getEnrolled", course_key)
|
|
2389
|
+
return output
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
/**
|
|
2393
|
+
* Enroll in an available course.
|
|
2394
|
+
*
|
|
2395
|
+
* 🔐 Authentication: user
|
|
2396
|
+
* No warnings
|
|
2397
|
+
*
|
|
2398
|
+
*/
|
|
2399
|
+
async enroll(course_key: string): Promise<void> {
|
|
2400
|
+
const [output, ofiles] = await this.root.execute("student.courses.enroll", course_key)
|
|
2401
|
+
return output
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
/**
|
|
2405
|
+
* Unenroll from an enrolled course.
|
|
2406
|
+
*
|
|
2407
|
+
* 🔐 Authentication: user
|
|
2408
|
+
* No warnings
|
|
2409
|
+
*
|
|
2410
|
+
*/
|
|
2411
|
+
async unenroll(course_key: string): Promise<void> {
|
|
2412
|
+
const [output, ofiles] = await this.root.execute("student.courses.unenroll", course_key)
|
|
2413
|
+
return output
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
/**
|
|
2418
|
+
*
|
|
2419
|
+
* No description yet
|
|
2420
|
+
*
|
|
2421
|
+
*/
|
|
2422
|
+
class Module_student_lists {
|
|
2423
|
+
private readonly root: JutgeApiClient
|
|
2424
|
+
|
|
2425
|
+
constructor(root: JutgeApiClient) {
|
|
2426
|
+
this.root = root
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
/**
|
|
2430
|
+
* Get all lists.
|
|
2431
|
+
*
|
|
2432
|
+
* 🔐 Authentication: user
|
|
2433
|
+
* No warnings
|
|
2434
|
+
*
|
|
2435
|
+
*/
|
|
2436
|
+
async getAll(): Promise<Record<string, BriefList>> {
|
|
2437
|
+
const [output, ofiles] = await this.root.execute("student.lists.getAll", null)
|
|
2438
|
+
return output
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
/**
|
|
2442
|
+
* Get a list.
|
|
2443
|
+
*
|
|
2444
|
+
* 🔐 Authentication: user
|
|
2445
|
+
* No warnings
|
|
2446
|
+
* Includes items, owner.
|
|
2447
|
+
*/
|
|
2448
|
+
async get(list_key: string): Promise<List> {
|
|
2449
|
+
const [output, ofiles] = await this.root.execute("student.lists.get", list_key)
|
|
2450
|
+
return output
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
/**
|
|
2455
|
+
*
|
|
2456
|
+
* ‼️ The state of this module is UNDER CONSTRUCTION. It is not ready for production use. The output of some function is capped if the exam has not started yet.
|
|
2457
|
+
*
|
|
2458
|
+
*/
|
|
2459
|
+
class Module_student_exam {
|
|
2460
|
+
private readonly root: JutgeApiClient
|
|
2461
|
+
|
|
2462
|
+
constructor(root: JutgeApiClient) {
|
|
2463
|
+
this.root = root
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
/**
|
|
2467
|
+
* Get list of ready exams.
|
|
2468
|
+
*
|
|
2469
|
+
* 🔐 Authentication: any
|
|
2470
|
+
* No warnings
|
|
2471
|
+
* An exam is ready if the current time is between its expected start time minus two days and its expected end time plus two days. Exams are sorted by their distance to the current time and by title order in case of ties.
|
|
2472
|
+
*/
|
|
2473
|
+
async getReadyExams(): Promise<ReadyExam[]> {
|
|
2474
|
+
const [output, ofiles] = await this.root.execute("student.exam.getReadyExams", null)
|
|
2475
|
+
return output
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
/**
|
|
2479
|
+
* Get current exam.
|
|
2480
|
+
*
|
|
2481
|
+
* 🔐 Authentication: exam
|
|
2482
|
+
* No warnings
|
|
2483
|
+
*
|
|
2484
|
+
*/
|
|
2485
|
+
async get(): Promise<RunningExam> {
|
|
2486
|
+
const [output, ofiles] = await this.root.execute("student.exam.get", null)
|
|
2487
|
+
return output
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
/**
|
|
2491
|
+
* Get a document in an exam.
|
|
2492
|
+
*
|
|
2493
|
+
* 🔐 Authentication: exam
|
|
2494
|
+
* No warnings
|
|
2495
|
+
*
|
|
2496
|
+
*/
|
|
2497
|
+
async getDocument(document_nm: string): Promise<RunningExamDocument> {
|
|
2498
|
+
const [output, ofiles] = await this.root.execute("student.exam.getDocument", document_nm)
|
|
2499
|
+
return output
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
/**
|
|
2503
|
+
* Get PDF of a document in an exam.
|
|
2504
|
+
*
|
|
2505
|
+
* 🔐 Authentication: exam
|
|
2506
|
+
* No warnings
|
|
2507
|
+
*
|
|
2508
|
+
*/
|
|
2509
|
+
async getDocumentPdf(document_nm: string): Promise<Download> {
|
|
2510
|
+
const [output, ofiles] = await this.root.execute("student.exam.getDocumentPdf", document_nm)
|
|
2511
|
+
return ofiles[0]
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
/**
|
|
2515
|
+
* Get ranking of the current contest.
|
|
2516
|
+
*
|
|
2517
|
+
* 🔐 Authentication: exam
|
|
2518
|
+
* No warnings
|
|
2519
|
+
*
|
|
2520
|
+
*/
|
|
2521
|
+
async getRanking(): Promise<Ranking> {
|
|
2522
|
+
const [output, ofiles] = await this.root.execute("student.exam.getRanking", null)
|
|
2523
|
+
return output
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
/**
|
|
2528
|
+
*
|
|
2529
|
+
* No description yet
|
|
2530
|
+
*
|
|
2531
|
+
*/
|
|
2532
|
+
class Module_student_statuses {
|
|
2533
|
+
private readonly root: JutgeApiClient
|
|
2534
|
+
|
|
2535
|
+
constructor(root: JutgeApiClient) {
|
|
2536
|
+
this.root = root
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
/**
|
|
2540
|
+
* Get statuses for all abstract problems.
|
|
2541
|
+
*
|
|
2542
|
+
* 🔐 Authentication: user
|
|
2543
|
+
* No warnings
|
|
2544
|
+
*
|
|
2545
|
+
*/
|
|
2546
|
+
async getAll(): Promise<Record<string, AbstractStatus>> {
|
|
2547
|
+
const [output, ofiles] = await this.root.execute("student.statuses.getAll", null)
|
|
2548
|
+
return output
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
/**
|
|
2552
|
+
* Get status for an abstract problem.
|
|
2553
|
+
*
|
|
2554
|
+
* 🔐 Authentication: user
|
|
2555
|
+
* No warnings
|
|
2556
|
+
*
|
|
2557
|
+
*/
|
|
2558
|
+
async getForAbstractProblem(problem_nm: string): Promise<AbstractStatus> {
|
|
2559
|
+
const [output, ofiles] = await this.root.execute("student.statuses.getForAbstractProblem", problem_nm)
|
|
2560
|
+
return output
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
/**
|
|
2564
|
+
* Get status for a problem.
|
|
2565
|
+
*
|
|
2566
|
+
* 🔐 Authentication: user
|
|
2567
|
+
* No warnings
|
|
2568
|
+
*
|
|
2569
|
+
*/
|
|
2570
|
+
async getForProblem(problem_id: string): Promise<Status> {
|
|
2571
|
+
const [output, ofiles] = await this.root.execute("student.statuses.getForProblem", problem_id)
|
|
2572
|
+
return output
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
/**
|
|
2577
|
+
*
|
|
2578
|
+
* This module is not yet finished.
|
|
2579
|
+
*
|
|
2580
|
+
*/
|
|
2581
|
+
class Module_student_awards {
|
|
2582
|
+
private readonly root: JutgeApiClient
|
|
2583
|
+
|
|
2584
|
+
constructor(root: JutgeApiClient) {
|
|
2585
|
+
this.root = root
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
/**
|
|
2589
|
+
* Get all awards.
|
|
2590
|
+
*
|
|
2591
|
+
* 🔐 Authentication: user
|
|
2592
|
+
* No warnings
|
|
2593
|
+
*
|
|
2594
|
+
*/
|
|
2595
|
+
async getAll(): Promise<Record<string, BriefAward>> {
|
|
2596
|
+
const [output, ofiles] = await this.root.execute("student.awards.getAll", null)
|
|
2597
|
+
return output
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* Get an award.
|
|
2602
|
+
*
|
|
2603
|
+
* 🔐 Authentication: user
|
|
2604
|
+
* No warnings
|
|
2605
|
+
*
|
|
2606
|
+
*/
|
|
2607
|
+
async get(award_id: string): Promise<Award> {
|
|
2608
|
+
const [output, ofiles] = await this.root.execute("student.awards.get", award_id)
|
|
2609
|
+
return output
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
/**
|
|
2614
|
+
*
|
|
2615
|
+
* This module is meant to be used by instructors
|
|
2616
|
+
*
|
|
2617
|
+
*/
|
|
2618
|
+
class Module_instructor {
|
|
2619
|
+
private readonly root: JutgeApiClient
|
|
2620
|
+
|
|
2621
|
+
readonly documents: Module_instructor_documents
|
|
2622
|
+
readonly lists: Module_instructor_lists
|
|
2623
|
+
readonly courses: Module_instructor_courses
|
|
2624
|
+
readonly exams: Module_instructor_exams
|
|
2625
|
+
readonly problems: Module_instructor_problems
|
|
2626
|
+
readonly queries: Module_instructor_queries
|
|
2627
|
+
readonly tags: Module_instructor_tags
|
|
2628
|
+
|
|
2629
|
+
constructor(root: JutgeApiClient) {
|
|
2630
|
+
this.root = root
|
|
2631
|
+
this.documents = new Module_instructor_documents(root)
|
|
2632
|
+
this.lists = new Module_instructor_lists(root)
|
|
2633
|
+
this.courses = new Module_instructor_courses(root)
|
|
2634
|
+
this.exams = new Module_instructor_exams(root)
|
|
2635
|
+
this.problems = new Module_instructor_problems(root)
|
|
2636
|
+
this.queries = new Module_instructor_queries(root)
|
|
2637
|
+
this.tags = new Module_instructor_tags(root)
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
/**
|
|
2642
|
+
*
|
|
2643
|
+
* No description yet
|
|
2644
|
+
*
|
|
2645
|
+
*/
|
|
2646
|
+
class Module_instructor_documents {
|
|
2647
|
+
private readonly root: JutgeApiClient
|
|
2648
|
+
|
|
2649
|
+
constructor(root: JutgeApiClient) {
|
|
2650
|
+
this.root = root
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
/**
|
|
2654
|
+
* Get index of all documents.
|
|
2655
|
+
*
|
|
2656
|
+
* 🔐 Authentication: instructor
|
|
2657
|
+
* No warnings
|
|
2658
|
+
*
|
|
2659
|
+
*/
|
|
2660
|
+
async index(): Promise<Record<string, Document>> {
|
|
2661
|
+
const [output, ofiles] = await this.root.execute("instructor.documents.index", null)
|
|
2662
|
+
return output
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
/**
|
|
2666
|
+
* Get a document.
|
|
2667
|
+
*
|
|
2668
|
+
* 🔐 Authentication: instructor
|
|
2669
|
+
* No warnings
|
|
2670
|
+
* The PDF file is not included in the response.
|
|
2671
|
+
*/
|
|
2672
|
+
async get(document_nm: string): Promise<Document> {
|
|
2673
|
+
const [output, ofiles] = await this.root.execute("instructor.documents.get", document_nm)
|
|
2674
|
+
return output
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
/**
|
|
2678
|
+
* Get PDF of a document.
|
|
2679
|
+
*
|
|
2680
|
+
* 🔐 Authentication: instructor
|
|
2681
|
+
* No warnings
|
|
2682
|
+
*
|
|
2683
|
+
*/
|
|
2684
|
+
async getPdf(document_nm: string): Promise<Download> {
|
|
2685
|
+
const [output, ofiles] = await this.root.execute("instructor.documents.getPdf", document_nm)
|
|
2686
|
+
return ofiles[0]
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
/**
|
|
2690
|
+
* Create a new document.
|
|
2691
|
+
*
|
|
2692
|
+
* 🔐 Authentication: instructor
|
|
2693
|
+
* No warnings
|
|
2694
|
+
*
|
|
2695
|
+
*/
|
|
2696
|
+
async create(data: DocumentCreation, ifile: File): Promise<void> {
|
|
2697
|
+
const [output, ofiles] = await this.root.execute("instructor.documents.create", data, [ifile])
|
|
2698
|
+
return output
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
/**
|
|
2702
|
+
* Update a document.
|
|
2703
|
+
*
|
|
2704
|
+
* 🔐 Authentication: instructor
|
|
2705
|
+
* No warnings
|
|
2706
|
+
*
|
|
2707
|
+
*/
|
|
2708
|
+
async update(data: DocumentCreation, ifile: File): Promise<void> {
|
|
2709
|
+
const [output, ofiles] = await this.root.execute("instructor.documents.update", data, [ifile])
|
|
2710
|
+
return output
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
/**
|
|
2714
|
+
* Remove a document.
|
|
2715
|
+
*
|
|
2716
|
+
* 🔐 Authentication: instructor
|
|
2717
|
+
* No warnings
|
|
2718
|
+
*
|
|
2719
|
+
*/
|
|
2720
|
+
async remove(document_nm: string): Promise<void> {
|
|
2721
|
+
const [output, ofiles] = await this.root.execute("instructor.documents.remove", document_nm)
|
|
2722
|
+
return output
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
/**
|
|
2727
|
+
*
|
|
2728
|
+
* No description yet
|
|
2729
|
+
*
|
|
2730
|
+
*/
|
|
2731
|
+
class Module_instructor_lists {
|
|
2732
|
+
private readonly root: JutgeApiClient
|
|
2733
|
+
|
|
2734
|
+
constructor(root: JutgeApiClient) {
|
|
2735
|
+
this.root = root
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
/**
|
|
2739
|
+
* Get index of all lists.
|
|
2740
|
+
*
|
|
2741
|
+
* 🔐 Authentication: instructor
|
|
2742
|
+
* No warnings
|
|
2743
|
+
*
|
|
2744
|
+
*/
|
|
2745
|
+
async index(): Promise<Record<string, InstructorBriefList>> {
|
|
2746
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.index", null)
|
|
2747
|
+
return output
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
/**
|
|
2751
|
+
* Get a list.
|
|
2752
|
+
*
|
|
2753
|
+
* 🔐 Authentication: instructor
|
|
2754
|
+
* No warnings
|
|
2755
|
+
*
|
|
2756
|
+
*/
|
|
2757
|
+
async get(list_nm: string): Promise<InstructorList> {
|
|
2758
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.get", list_nm)
|
|
2759
|
+
return output
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
/**
|
|
2763
|
+
* Create a new list.
|
|
2764
|
+
*
|
|
2765
|
+
* 🔐 Authentication: instructor
|
|
2766
|
+
* No warnings
|
|
2767
|
+
*
|
|
2768
|
+
*/
|
|
2769
|
+
async create(data: InstructorListCreation): Promise<void> {
|
|
2770
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.create", data)
|
|
2771
|
+
return output
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
/**
|
|
2775
|
+
* Update an existing list.
|
|
2776
|
+
*
|
|
2777
|
+
* 🔐 Authentication: instructor
|
|
2778
|
+
* No warnings
|
|
2779
|
+
*
|
|
2780
|
+
*/
|
|
2781
|
+
async update(data: InstructorListCreation): Promise<void> {
|
|
2782
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.update", data)
|
|
2783
|
+
return output
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
/**
|
|
2787
|
+
* Delete an existing list.
|
|
2788
|
+
*
|
|
2789
|
+
* 🔐 Authentication: instructor
|
|
2790
|
+
* No warnings
|
|
2791
|
+
*
|
|
2792
|
+
*/
|
|
2793
|
+
async remove(list_nm: string): Promise<void> {
|
|
2794
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.remove", list_nm)
|
|
2795
|
+
return output
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
/**
|
|
2799
|
+
* Get the list of lists that are archived.
|
|
2800
|
+
*
|
|
2801
|
+
* 🔐 Authentication: instructor
|
|
2802
|
+
* No warnings
|
|
2803
|
+
* At some point, endpoints related to archiving lists should change as the archive bit will be an attribute of each list.
|
|
2804
|
+
*/
|
|
2805
|
+
async getArchived(): Promise<string[]> {
|
|
2806
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.getArchived", null)
|
|
2807
|
+
return output
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
/**
|
|
2811
|
+
* Archive a list.
|
|
2812
|
+
*
|
|
2813
|
+
* 🔐 Authentication: instructor
|
|
2814
|
+
* No warnings
|
|
2815
|
+
*
|
|
2816
|
+
*/
|
|
2817
|
+
async archive(list_nm: string): Promise<void> {
|
|
2818
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.archive", list_nm)
|
|
2819
|
+
return output
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
/**
|
|
2823
|
+
* Unarchive a list.
|
|
2824
|
+
*
|
|
2825
|
+
* 🔐 Authentication: instructor
|
|
2826
|
+
* No warnings
|
|
2827
|
+
*
|
|
2828
|
+
*/
|
|
2829
|
+
async unarchive(list_nm: string): Promise<void> {
|
|
2830
|
+
const [output, ofiles] = await this.root.execute("instructor.lists.unarchive", list_nm)
|
|
2831
|
+
return output
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
/**
|
|
2836
|
+
*
|
|
2837
|
+
*
|
|
2838
|
+
This module manages the courses that an instructor is teaching. It allows the instructor to manage the course, including getting and updating its lists, students and tutors. It can also send invites to pending students and tutors.
|
|
2839
|
+
|
|
2840
|
+
The course name is a unique slug for the course. It is used to reference the course in the system.
|
|
2841
|
+
|
|
2842
|
+
The course title is the human-readable title of the course.
|
|
2843
|
+
|
|
2844
|
+
The course description is a human-readable description of the course.
|
|
2845
|
+
|
|
2846
|
+
Students and tutors are managed in three lists: invited, enrolled and pending. These contains the emails of these users. Invited students and tutors are those who have been invited to the course. Enrolled students and tutors are those who have accepted the invitation and are part of the course. Pending students and tutors are those who have been invited to join the course but have not yet accepted. Enrolled and pending students and tutors are managed by the system and cannot not be modified directly.
|
|
2847
|
+
|
|
2848
|
+
*
|
|
2849
|
+
*/
|
|
2850
|
+
class Module_instructor_courses {
|
|
2851
|
+
private readonly root: JutgeApiClient
|
|
2852
|
+
|
|
2853
|
+
constructor(root: JutgeApiClient) {
|
|
2854
|
+
this.root = root
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
/**
|
|
2858
|
+
* Get index of all courses.
|
|
2859
|
+
*
|
|
2860
|
+
* 🔐 Authentication: instructor
|
|
2861
|
+
* No warnings
|
|
2862
|
+
*
|
|
2863
|
+
*/
|
|
2864
|
+
async index(): Promise<Record<string, InstructorBriefCourse>> {
|
|
2865
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.index", null)
|
|
2866
|
+
return output
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
/**
|
|
2870
|
+
* Get a course.
|
|
2871
|
+
*
|
|
2872
|
+
* 🔐 Authentication: instructor
|
|
2873
|
+
* No warnings
|
|
2874
|
+
*
|
|
2875
|
+
*/
|
|
2876
|
+
async get(course_nm: string): Promise<InstructorCourse> {
|
|
2877
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.get", course_nm)
|
|
2878
|
+
return output
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
/**
|
|
2882
|
+
* Create a new course.
|
|
2883
|
+
*
|
|
2884
|
+
* 🔐 Authentication: instructor
|
|
2885
|
+
* No warnings
|
|
2886
|
+
* Only invited students and tutors are taken into account. Enrolled and pending students and tutors are ignored, as these are managed by the system.
|
|
2887
|
+
*/
|
|
2888
|
+
async create(data: InstructorCourseCreation): Promise<void> {
|
|
2889
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.create", data)
|
|
2890
|
+
return output
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
/**
|
|
2894
|
+
* Update an existing course.
|
|
2895
|
+
*
|
|
2896
|
+
* 🔐 Authentication: instructor
|
|
2897
|
+
* No warnings
|
|
2898
|
+
* Only invited students and tutors are taken into account. Enrolled and pending students and tutors are ignored, as these are managed by the system.
|
|
2899
|
+
*/
|
|
2900
|
+
async update(data: InstructorCourseUpdate): Promise<void> {
|
|
2901
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.update", data)
|
|
2902
|
+
return output
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
/**
|
|
2906
|
+
* Delete an existing course.
|
|
2907
|
+
*
|
|
2908
|
+
* 🔐 Authentication: instructor
|
|
2909
|
+
* No warnings
|
|
2910
|
+
* A course should not be deleted. Ask a system administrator to remove it if you really need it.
|
|
2911
|
+
*/
|
|
2912
|
+
async remove(course_nm: string): Promise<void> {
|
|
2913
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.remove", course_nm)
|
|
2914
|
+
return output
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
/**
|
|
2918
|
+
* Send invite email to pending students in the course.
|
|
2919
|
+
*
|
|
2920
|
+
* 🔐 Authentication: instructor
|
|
2921
|
+
* No warnings
|
|
2922
|
+
* Please do not abuse.
|
|
2923
|
+
*/
|
|
2924
|
+
async sendInviteToStudents(course_nm: string): Promise<void> {
|
|
2925
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.sendInviteToStudents", course_nm)
|
|
2926
|
+
return output
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
/**
|
|
2930
|
+
* Send invite email to pending tutors in the course.
|
|
2931
|
+
*
|
|
2932
|
+
* 🔐 Authentication: instructor
|
|
2933
|
+
* No warnings
|
|
2934
|
+
* Please do not abuse.
|
|
2935
|
+
*/
|
|
2936
|
+
async sendInviteToTutors(course_nm: string): Promise<void> {
|
|
2937
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.sendInviteToTutors", course_nm)
|
|
2938
|
+
return output
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
/**
|
|
2942
|
+
* Get the profiles of the students enrolled in the course.
|
|
2943
|
+
*
|
|
2944
|
+
* 🔐 Authentication: instructor
|
|
2945
|
+
* No warnings
|
|
2946
|
+
*
|
|
2947
|
+
*/
|
|
2948
|
+
async getStudentProfiles(course_nm: string): Promise<Record<string, StudentProfile>> {
|
|
2949
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.getStudentProfiles", course_nm)
|
|
2950
|
+
return output
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
/**
|
|
2954
|
+
* Get the profiles of the tutors enrolled in the course.
|
|
2955
|
+
*
|
|
2956
|
+
* 🔐 Authentication: instructor
|
|
2957
|
+
* No warnings
|
|
2958
|
+
*
|
|
2959
|
+
*/
|
|
2960
|
+
async getTutorProfiles(course_nm: string): Promise<Record<string, StudentProfile>> {
|
|
2961
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.getTutorProfiles", course_nm)
|
|
2962
|
+
return output
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
/**
|
|
2966
|
+
* Get the list of courses that are archived.
|
|
2967
|
+
*
|
|
2968
|
+
* 🔐 Authentication: instructor
|
|
2969
|
+
* No warnings
|
|
2970
|
+
* At some point, endpoints related to archiving courses should change as the archive bit will be an attribute of each course.
|
|
2971
|
+
*/
|
|
2972
|
+
async getArchived(): Promise<string[]> {
|
|
2973
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.getArchived", null)
|
|
2974
|
+
return output
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
/**
|
|
2978
|
+
* Archive a course.
|
|
2979
|
+
*
|
|
2980
|
+
* 🔐 Authentication: instructor
|
|
2981
|
+
* No warnings
|
|
2982
|
+
*
|
|
2983
|
+
*/
|
|
2984
|
+
async archive(course_nm: string): Promise<void> {
|
|
2985
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.archive", course_nm)
|
|
2986
|
+
return output
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
/**
|
|
2990
|
+
* Unarchive a course.
|
|
2991
|
+
*
|
|
2992
|
+
* 🔐 Authentication: instructor
|
|
2993
|
+
* No warnings
|
|
2994
|
+
*
|
|
2995
|
+
*/
|
|
2996
|
+
async unarchive(course_nm: string): Promise<void> {
|
|
2997
|
+
const [output, ofiles] = await this.root.execute("instructor.courses.unarchive", course_nm)
|
|
2998
|
+
return output
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
/**
|
|
3003
|
+
*
|
|
3004
|
+
*
|
|
3005
|
+
|
|
3006
|
+
This module manages the exams that an instructor is teaching. It allows the instructor to manage the exam, including getting and updating its documents, problems, students and submissions.
|
|
3007
|
+
|
|
3008
|
+
Exams objects are quite complex. Thus, this interface is also a bit complex. Each part of an exam can be get or updated in a separate endpoint. The main endpoint is the get endpoint, which returns the full exam object.
|
|
3009
|
+
|
|
3010
|
+
*
|
|
3011
|
+
*/
|
|
3012
|
+
class Module_instructor_exams {
|
|
3013
|
+
private readonly root: JutgeApiClient
|
|
3014
|
+
|
|
3015
|
+
constructor(root: JutgeApiClient) {
|
|
3016
|
+
this.root = root
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
/**
|
|
3020
|
+
* Get index of all exams.
|
|
3021
|
+
*
|
|
3022
|
+
* 🔐 Authentication: instructor
|
|
3023
|
+
* No warnings
|
|
3024
|
+
*
|
|
3025
|
+
*/
|
|
3026
|
+
async index(): Promise<Record<string, InstructorBriefExam>> {
|
|
3027
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.index", null)
|
|
3028
|
+
return output
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
/**
|
|
3032
|
+
* Get an exam.
|
|
3033
|
+
*
|
|
3034
|
+
* 🔐 Authentication: instructor
|
|
3035
|
+
* No warnings
|
|
3036
|
+
*
|
|
3037
|
+
*/
|
|
3038
|
+
async get(exam_nm: string): Promise<InstructorExam> {
|
|
3039
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.get", exam_nm)
|
|
3040
|
+
return output
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
/**
|
|
3044
|
+
* Get documents of an exam.
|
|
3045
|
+
*
|
|
3046
|
+
* 🔐 Authentication: instructor
|
|
3047
|
+
* No warnings
|
|
3048
|
+
*
|
|
3049
|
+
*/
|
|
3050
|
+
async getDocuments(exam_nm: string): Promise<RunningExamDocument[]> {
|
|
3051
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getDocuments", exam_nm)
|
|
3052
|
+
return output
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
/**
|
|
3056
|
+
* Get problems of an exam.
|
|
3057
|
+
*
|
|
3058
|
+
* 🔐 Authentication: instructor
|
|
3059
|
+
* No warnings
|
|
3060
|
+
*
|
|
3061
|
+
*/
|
|
3062
|
+
async getProblems(exam_nm: string): Promise<InstructorExamProblem[]> {
|
|
3063
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getProblems", exam_nm)
|
|
3064
|
+
return output
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
/**
|
|
3068
|
+
* Get students of an exam.
|
|
3069
|
+
*
|
|
3070
|
+
* 🔐 Authentication: instructor
|
|
3071
|
+
* No warnings
|
|
3072
|
+
*
|
|
3073
|
+
*/
|
|
3074
|
+
async getStudents(exam_nm: string): Promise<InstructorExamStudent[]> {
|
|
3075
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getStudents", exam_nm)
|
|
3076
|
+
return output
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
/**
|
|
3080
|
+
* Get an student of an exam.
|
|
3081
|
+
*
|
|
3082
|
+
* 🔐 Authentication: instructor
|
|
3083
|
+
* No warnings
|
|
3084
|
+
*
|
|
3085
|
+
*/
|
|
3086
|
+
async getStudent(data: { exam_nm: string; email: string }): Promise<InstructorExamStudent> {
|
|
3087
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getStudent", data)
|
|
3088
|
+
return output
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
/**
|
|
3092
|
+
* Get submissions of an exam as a webstream.
|
|
3093
|
+
*
|
|
3094
|
+
* 🔐 Authentication: instructor
|
|
3095
|
+
* No warnings
|
|
3096
|
+
* Meant for real-time streaming of submissions, most instructors will possibly prefer getSubmissionsPack.
|
|
3097
|
+
*/
|
|
3098
|
+
async getSubmissions(data: { exam_nm: string; options: InstructorExamSubmissionsOptions }): Promise<WebStream> {
|
|
3099
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getSubmissions", data)
|
|
3100
|
+
return output
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
/**
|
|
3104
|
+
* Get submissions of an exam as a pack.
|
|
3105
|
+
*
|
|
3106
|
+
* 🔐 Authentication: instructor
|
|
3107
|
+
* No warnings
|
|
3108
|
+
* This endpoint will prepare the pack in the background and return a link to download it later. Packs take some time to be prepared, and are deleted after 24 hours. This is the preferred endpoint for most instructors, as it is simpler to use than getSubmissions.
|
|
3109
|
+
*/
|
|
3110
|
+
async getSubmissionsPack(data: { exam_nm: string; options: InstructorExamSubmissionsOptions }): Promise<Pack> {
|
|
3111
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getSubmissionsPack", data)
|
|
3112
|
+
return output
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
/**
|
|
3116
|
+
* Get statistics of an exam.
|
|
3117
|
+
*
|
|
3118
|
+
* 🔐 Authentication: instructor
|
|
3119
|
+
* No warnings
|
|
3120
|
+
*
|
|
3121
|
+
*/
|
|
3122
|
+
async getStatistics(exam_nm: string): Promise<ExamStatistics> {
|
|
3123
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getStatistics", exam_nm)
|
|
3124
|
+
return output
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
/**
|
|
3128
|
+
* Create a new exam.
|
|
3129
|
+
*
|
|
3130
|
+
* 🔐 Authentication: instructor
|
|
3131
|
+
* No warnings
|
|
3132
|
+
*
|
|
3133
|
+
*/
|
|
3134
|
+
async create(data: InstructorExamCreation): Promise<void> {
|
|
3135
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.create", data)
|
|
3136
|
+
return output
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
/**
|
|
3140
|
+
* Update an existing exam.
|
|
3141
|
+
*
|
|
3142
|
+
* 🔐 Authentication: instructor
|
|
3143
|
+
* No warnings
|
|
3144
|
+
*
|
|
3145
|
+
*/
|
|
3146
|
+
async update(data: InstructorExamUpdate): Promise<void> {
|
|
3147
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.update", data)
|
|
3148
|
+
return output
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
/**
|
|
3152
|
+
* Update documents of an exam.
|
|
3153
|
+
*
|
|
3154
|
+
* 🔐 Authentication: instructor
|
|
3155
|
+
* No warnings
|
|
3156
|
+
*
|
|
3157
|
+
*/
|
|
3158
|
+
async updateDocuments(data: { exam_nm: string; document_nms: string[] }): Promise<void> {
|
|
3159
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.updateDocuments", data)
|
|
3160
|
+
return output
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
/**
|
|
3164
|
+
* Update compilers of an exam.
|
|
3165
|
+
*
|
|
3166
|
+
* 🔐 Authentication: instructor
|
|
3167
|
+
* No warnings
|
|
3168
|
+
*
|
|
3169
|
+
*/
|
|
3170
|
+
async updateCompilers(data: { exam_nm: string; compiler_ids: string[] }): Promise<void> {
|
|
3171
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.updateCompilers", data)
|
|
3172
|
+
return output
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
/**
|
|
3176
|
+
* Update problems of an exam.
|
|
3177
|
+
*
|
|
3178
|
+
* 🔐 Authentication: instructor
|
|
3179
|
+
* No warnings
|
|
3180
|
+
*
|
|
3181
|
+
*/
|
|
3182
|
+
async updateProblems(data: { exam_nm: string; problems: InstructorExamProblem[] }): Promise<void> {
|
|
3183
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.updateProblems", data)
|
|
3184
|
+
return output
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
/**
|
|
3188
|
+
* Update students of an exam.
|
|
3189
|
+
*
|
|
3190
|
+
* 🔐 Authentication: instructor
|
|
3191
|
+
* No warnings
|
|
3192
|
+
*
|
|
3193
|
+
*/
|
|
3194
|
+
async updateStudents(data: { exam_nm: string; students: InstructorExamStudent[] }): Promise<void> {
|
|
3195
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.updateStudents", data)
|
|
3196
|
+
return output
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
/**
|
|
3200
|
+
* Add students to an exam.
|
|
3201
|
+
*
|
|
3202
|
+
* 🔐 Authentication: instructor
|
|
3203
|
+
* No warnings
|
|
3204
|
+
*
|
|
3205
|
+
*/
|
|
3206
|
+
async addStudents(data: { exam_nm: string; students: InstructorExamStudent[] }): Promise<void> {
|
|
3207
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.addStudents", data)
|
|
3208
|
+
return output
|
|
3209
|
+
}
|
|
3210
|
+
|
|
3211
|
+
/**
|
|
3212
|
+
* Remove students from an exam.
|
|
3213
|
+
*
|
|
3214
|
+
* 🔐 Authentication: instructor
|
|
3215
|
+
* No warnings
|
|
3216
|
+
*
|
|
3217
|
+
*/
|
|
3218
|
+
async removeStudents(data: { exam_nm: string; emails: string[] }): Promise<void> {
|
|
3219
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.removeStudents", data)
|
|
3220
|
+
return output
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
/**
|
|
3224
|
+
* Delete an existing exam.
|
|
3225
|
+
*
|
|
3226
|
+
* 🔐 Authentication: instructor
|
|
3227
|
+
* No warnings
|
|
3228
|
+
* Note: An exam can only be deleted if it has not started.
|
|
3229
|
+
*/
|
|
3230
|
+
async remove(exam_nm: string): Promise<void> {
|
|
3231
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.remove", exam_nm)
|
|
3232
|
+
return output
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
/**
|
|
3236
|
+
* Get the list of exams that are archived.
|
|
3237
|
+
*
|
|
3238
|
+
* 🔐 Authentication: instructor
|
|
3239
|
+
* No warnings
|
|
3240
|
+
* At some point, endpoints related to archiving exams should change as the archive bit will be an attribute of each exam.
|
|
3241
|
+
*/
|
|
3242
|
+
async getArchived(): Promise<string[]> {
|
|
3243
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getArchived", null)
|
|
3244
|
+
return output
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3247
|
+
/**
|
|
3248
|
+
* Archive an exam.
|
|
3249
|
+
*
|
|
3250
|
+
* 🔐 Authentication: instructor
|
|
3251
|
+
* No warnings
|
|
3252
|
+
*
|
|
3253
|
+
*/
|
|
3254
|
+
async archive(exam_nm: string): Promise<void> {
|
|
3255
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.archive", exam_nm)
|
|
3256
|
+
return output
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
/**
|
|
3260
|
+
* Unarchive an exam.
|
|
3261
|
+
*
|
|
3262
|
+
* 🔐 Authentication: instructor
|
|
3263
|
+
* No warnings
|
|
3264
|
+
*
|
|
3265
|
+
*/
|
|
3266
|
+
async unarchive(exam_nm: string): Promise<void> {
|
|
3267
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.unarchive", exam_nm)
|
|
3268
|
+
return output
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
/**
|
|
3272
|
+
* Get the ranking.
|
|
3273
|
+
*
|
|
3274
|
+
* 🔐 Authentication: instructor
|
|
3275
|
+
* No warnings
|
|
3276
|
+
* Under development.
|
|
3277
|
+
*/
|
|
3278
|
+
async getRanking(exam_nm: string): Promise<Ranking> {
|
|
3279
|
+
const [output, ofiles] = await this.root.execute("instructor.exams.getRanking", exam_nm)
|
|
3280
|
+
return output
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
|
|
3284
|
+
/**
|
|
3285
|
+
*
|
|
3286
|
+
* No description yet
|
|
3287
|
+
*
|
|
3288
|
+
*/
|
|
3289
|
+
class Module_instructor_problems {
|
|
3290
|
+
private readonly root: JutgeApiClient
|
|
3291
|
+
|
|
3292
|
+
constructor(root: JutgeApiClient) {
|
|
3293
|
+
this.root = root
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
/**
|
|
3297
|
+
* Get the list of own problems.
|
|
3298
|
+
*
|
|
3299
|
+
* 🔐 Authentication: instructor
|
|
3300
|
+
* No warnings
|
|
3301
|
+
*
|
|
3302
|
+
*/
|
|
3303
|
+
async getOwnProblems(): Promise<string[]> {
|
|
3304
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.getOwnProblems", null)
|
|
3305
|
+
return output
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
/**
|
|
3309
|
+
* Get the list of own problems that have a passcode.
|
|
3310
|
+
*
|
|
3311
|
+
* 🔐 Authentication: instructor
|
|
3312
|
+
* No warnings
|
|
3313
|
+
*
|
|
3314
|
+
*/
|
|
3315
|
+
async getOwnProblemsWithPasscode(): Promise<string[]> {
|
|
3316
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.getOwnProblemsWithPasscode", null)
|
|
3317
|
+
return output
|
|
3318
|
+
}
|
|
3319
|
+
|
|
3320
|
+
/**
|
|
3321
|
+
* Get the passcode of a problem.
|
|
3322
|
+
*
|
|
3323
|
+
* 🔐 Authentication: instructor
|
|
3324
|
+
* No warnings
|
|
3325
|
+
* Returns an empty string if the problem has no passcode.
|
|
3326
|
+
*/
|
|
3327
|
+
async getPasscode(problem_nm: string): Promise<string> {
|
|
3328
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.getPasscode", problem_nm)
|
|
3329
|
+
return output
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
/**
|
|
3333
|
+
* Set or update the passcode of a problem.
|
|
3334
|
+
*
|
|
3335
|
+
* 🔐 Authentication: instructor
|
|
3336
|
+
* No warnings
|
|
3337
|
+
* The passcode must be at least 8 characters long and contain only alphanumeric characters. The passcode will be stored in the database in plain text.
|
|
3338
|
+
*/
|
|
3339
|
+
async setPasscode(data: { problem_nm: string; passcode: string }): Promise<void> {
|
|
3340
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.setPasscode", data)
|
|
3341
|
+
return output
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
/**
|
|
3345
|
+
* Remove passcode of a problem.
|
|
3346
|
+
*
|
|
3347
|
+
* 🔐 Authentication: instructor
|
|
3348
|
+
* No warnings
|
|
3349
|
+
*
|
|
3350
|
+
*/
|
|
3351
|
+
async removePasscode(problem_nm: string): Promise<void> {
|
|
3352
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.removePasscode", problem_nm)
|
|
3353
|
+
return output
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
/**
|
|
3357
|
+
* Share passcode to a list of users identified by their email.
|
|
3358
|
+
*
|
|
3359
|
+
* 🔐 Authentication: instructor
|
|
3360
|
+
* No warnings
|
|
3361
|
+
* No emails are sent. Emails that are not registered in the system are ignored.
|
|
3362
|
+
*/
|
|
3363
|
+
async sharePasscode(data: { problem_nm: string; emails: string[] }): Promise<void> {
|
|
3364
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.sharePasscode", data)
|
|
3365
|
+
return output
|
|
3366
|
+
}
|
|
3367
|
+
|
|
3368
|
+
/**
|
|
3369
|
+
* Deprecate a problem.
|
|
3370
|
+
*
|
|
3371
|
+
* 🔐 Authentication: instructor
|
|
3372
|
+
* No warnings
|
|
3373
|
+
*
|
|
3374
|
+
*/
|
|
3375
|
+
async deprecate(data: { problem_nm: string; reason: string }): Promise<void> {
|
|
3376
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.deprecate", data)
|
|
3377
|
+
return output
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
/**
|
|
3381
|
+
* Undeprecate a problem.
|
|
3382
|
+
*
|
|
3383
|
+
* 🔐 Authentication: instructor
|
|
3384
|
+
* No warnings
|
|
3385
|
+
*
|
|
3386
|
+
*/
|
|
3387
|
+
async undeprecate(problem_nm: string): Promise<void> {
|
|
3388
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.undeprecate", problem_nm)
|
|
3389
|
+
return output
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
/**
|
|
3393
|
+
* Download a problem as a ZIP file.
|
|
3394
|
+
*
|
|
3395
|
+
* 🔐 Authentication: instructor
|
|
3396
|
+
* No warnings
|
|
3397
|
+
* Quick and dirty implementation, should be improved. Returns a ZIP file with the abstract problem and all its problems.
|
|
3398
|
+
*/
|
|
3399
|
+
async download(problem_nm: string): Promise<Download> {
|
|
3400
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.download", problem_nm)
|
|
3401
|
+
return ofiles[0]
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
/**
|
|
3405
|
+
* Create a problem from a ZIP archive using old PHP code.
|
|
3406
|
+
*
|
|
3407
|
+
* 🔐 Authentication: instructor
|
|
3408
|
+
* No warnings
|
|
3409
|
+
* At some point, this endpoint will be deprecated. It is a bit slow (about one minute). Returns the problem_nm of the new problem. Does not provide any feedback.
|
|
3410
|
+
*/
|
|
3411
|
+
async legacyCreate(passcode: string, ifile: File): Promise<string> {
|
|
3412
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.legacyCreate", passcode, [ifile])
|
|
3413
|
+
return output
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
/**
|
|
3417
|
+
* Update a problem from a ZIP archive using old PHP code.
|
|
3418
|
+
*
|
|
3419
|
+
* 🔐 Authentication: instructor
|
|
3420
|
+
* No warnings
|
|
3421
|
+
* At some point, this endpoint will be deprecated. Does not provide any feedback.
|
|
3422
|
+
*/
|
|
3423
|
+
async legacyUpdate(problem_nm: string, ifile: File): Promise<void> {
|
|
3424
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.legacyUpdate", problem_nm, [ifile])
|
|
3425
|
+
return output
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
/**
|
|
3429
|
+
* Create a problem from a ZIP archive using old PHP code using terminal streaming.
|
|
3430
|
+
*
|
|
3431
|
+
* 🔐 Authentication: instructor
|
|
3432
|
+
* No warnings
|
|
3433
|
+
* At some point, this endpoint will be deprecated. Returns a Terminal from which the problem feedback is streamed.
|
|
3434
|
+
*/
|
|
3435
|
+
async legacyCreateWithTerminal(passcode: string, ifile: File): Promise<WebStream> {
|
|
3436
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.legacyCreateWithTerminal", passcode, [
|
|
3437
|
+
ifile,
|
|
3438
|
+
])
|
|
3439
|
+
return output
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
/**
|
|
3443
|
+
* Update a problem from a ZIP archive using old PHP code using terminal streaming.
|
|
3444
|
+
*
|
|
3445
|
+
* 🔐 Authentication: instructor
|
|
3446
|
+
* No warnings
|
|
3447
|
+
* At some point, this endpoint will be deprecated. Returns an id from which the problem feedback is streamed under /terminals.
|
|
3448
|
+
*/
|
|
3449
|
+
async legacyUpdateWithTerminal(problem_nm: string, ifile: File): Promise<WebStream> {
|
|
3450
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.legacyUpdateWithTerminal", problem_nm, [
|
|
3451
|
+
ifile,
|
|
3452
|
+
])
|
|
3453
|
+
return output
|
|
3454
|
+
}
|
|
3455
|
+
|
|
3456
|
+
/**
|
|
3457
|
+
* Generate a problem with JutgeAI. The result is sent by email when ready.
|
|
3458
|
+
*
|
|
3459
|
+
* 🔐 Authentication: instructor
|
|
3460
|
+
* ❌ Warning: experimental
|
|
3461
|
+
*
|
|
3462
|
+
*/
|
|
3463
|
+
async generateProblemWithJutgeAI(data: ProblemGenerationInfo): Promise<string> {
|
|
3464
|
+
const [output, ofiles] = await this.root.execute("instructor.problems.generateProblemWithJutgeAI", data)
|
|
3465
|
+
return output
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/**
|
|
3470
|
+
*
|
|
3471
|
+
* No description yet
|
|
3472
|
+
*
|
|
3473
|
+
*/
|
|
3474
|
+
class Module_instructor_queries {
|
|
3475
|
+
private readonly root: JutgeApiClient
|
|
3476
|
+
|
|
3477
|
+
constructor(root: JutgeApiClient) {
|
|
3478
|
+
this.root = root
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
/**
|
|
3482
|
+
* Get submissions for a problem in a course.
|
|
3483
|
+
*
|
|
3484
|
+
* 🔐 Authentication: instructor
|
|
3485
|
+
* No warnings
|
|
3486
|
+
* Returns a list of submissions for a given problem for all students of a given course. Each submission includes the email, time, problem name, problem id, verdict, and IP address. The list is ordered by email and time. Known as ricard01 in the past.
|
|
3487
|
+
*/
|
|
3488
|
+
async getCourseProblemSubmissions(data: { course_nm: string; problem_nm: string }): Promise<SubmissionsQuery> {
|
|
3489
|
+
const [output, ofiles] = await this.root.execute("instructor.queries.getCourseProblemSubmissions", data)
|
|
3490
|
+
return output
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3493
|
+
/**
|
|
3494
|
+
* Get submissions for all problems in a list in a course.
|
|
3495
|
+
*
|
|
3496
|
+
* 🔐 Authentication: instructor
|
|
3497
|
+
* No warnings
|
|
3498
|
+
* Returns a list of submissions for all problems in a given list for all students of a given course. Each submission includes the email, time, problem name, problem id, verdict, and IP address. The list is ordered by email, problem id and time. Known as ricard02 in the past.
|
|
3499
|
+
*/
|
|
3500
|
+
async getCourseListSubmissions(data: { course_nm: string; list_nm: string }): Promise<SubmissionsQuery> {
|
|
3501
|
+
const [output, ofiles] = await this.root.execute("instructor.queries.getCourseListSubmissions", data)
|
|
3502
|
+
return output
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
/**
|
|
3507
|
+
*
|
|
3508
|
+
* No description yet
|
|
3509
|
+
*
|
|
3510
|
+
*/
|
|
3511
|
+
class Module_instructor_tags {
|
|
3512
|
+
private readonly root: JutgeApiClient
|
|
3513
|
+
|
|
3514
|
+
constructor(root: JutgeApiClient) {
|
|
3515
|
+
this.root = root
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
/**
|
|
3519
|
+
* Get list of all tags.
|
|
3520
|
+
*
|
|
3521
|
+
* 🔐 Authentication: instructor
|
|
3522
|
+
* No warnings
|
|
3523
|
+
*
|
|
3524
|
+
*/
|
|
3525
|
+
async index(): Promise<string[]> {
|
|
3526
|
+
const [output, ofiles] = await this.root.execute("instructor.tags.index", null)
|
|
3527
|
+
return output
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
/**
|
|
3531
|
+
* Get all tags with their problems.
|
|
3532
|
+
*
|
|
3533
|
+
* 🔐 Authentication: instructor
|
|
3534
|
+
* No warnings
|
|
3535
|
+
*
|
|
3536
|
+
*/
|
|
3537
|
+
async getDict(): Promise<TagsDict> {
|
|
3538
|
+
const [output, ofiles] = await this.root.execute("instructor.tags.getDict", null)
|
|
3539
|
+
return output
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
/**
|
|
3543
|
+
* Get all problems with a given tag.
|
|
3544
|
+
*
|
|
3545
|
+
* 🔐 Authentication: instructor
|
|
3546
|
+
* No warnings
|
|
3547
|
+
*
|
|
3548
|
+
*/
|
|
3549
|
+
async get(tag: string): Promise<string[]> {
|
|
3550
|
+
const [output, ofiles] = await this.root.execute("instructor.tags.get", tag)
|
|
3551
|
+
return output
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3555
|
+
/**
|
|
3556
|
+
*
|
|
3557
|
+
* Module with administration endpoints. Not meant for regular users. It still lacks lots of endpoints
|
|
3558
|
+
*
|
|
3559
|
+
*/
|
|
3560
|
+
class Module_admin {
|
|
3561
|
+
private readonly root: JutgeApiClient
|
|
3562
|
+
|
|
3563
|
+
readonly instructors: Module_admin_instructors
|
|
3564
|
+
readonly users: Module_admin_users
|
|
3565
|
+
readonly dashboard: Module_admin_dashboard
|
|
3566
|
+
readonly queue: Module_admin_queue
|
|
3567
|
+
readonly tasks: Module_admin_tasks
|
|
3568
|
+
readonly stats: Module_admin_stats
|
|
3569
|
+
readonly problems: Module_admin_problems
|
|
3570
|
+
|
|
3571
|
+
constructor(root: JutgeApiClient) {
|
|
3572
|
+
this.root = root
|
|
3573
|
+
this.instructors = new Module_admin_instructors(root)
|
|
3574
|
+
this.users = new Module_admin_users(root)
|
|
3575
|
+
this.dashboard = new Module_admin_dashboard(root)
|
|
3576
|
+
this.queue = new Module_admin_queue(root)
|
|
3577
|
+
this.tasks = new Module_admin_tasks(root)
|
|
3578
|
+
this.stats = new Module_admin_stats(root)
|
|
3579
|
+
this.problems = new Module_admin_problems(root)
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
/**
|
|
3584
|
+
*
|
|
3585
|
+
* No description yet
|
|
3586
|
+
*
|
|
3587
|
+
*/
|
|
3588
|
+
class Module_admin_instructors {
|
|
3589
|
+
private readonly root: JutgeApiClient
|
|
3590
|
+
|
|
3591
|
+
constructor(root: JutgeApiClient) {
|
|
3592
|
+
this.root = root
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3595
|
+
/**
|
|
3596
|
+
* Get instructors.
|
|
3597
|
+
*
|
|
3598
|
+
* 🔐 Authentication: admin
|
|
3599
|
+
* No warnings
|
|
3600
|
+
*
|
|
3601
|
+
*/
|
|
3602
|
+
async get(): Promise<InstructorEntries> {
|
|
3603
|
+
const [output, ofiles] = await this.root.execute("admin.instructors.get", null)
|
|
3604
|
+
return output
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
/**
|
|
3608
|
+
* Add an instructor.
|
|
3609
|
+
*
|
|
3610
|
+
* 🔐 Authentication: admin
|
|
3611
|
+
* No warnings
|
|
3612
|
+
*
|
|
3613
|
+
*/
|
|
3614
|
+
async add(data: { email: string; username: string }): Promise<void> {
|
|
3615
|
+
const [output, ofiles] = await this.root.execute("admin.instructors.add", data)
|
|
3616
|
+
return output
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
/**
|
|
3620
|
+
* Remove an instructor.
|
|
3621
|
+
*
|
|
3622
|
+
* 🔐 Authentication: admin
|
|
3623
|
+
* No warnings
|
|
3624
|
+
*
|
|
3625
|
+
*/
|
|
3626
|
+
async remove(email: string): Promise<void> {
|
|
3627
|
+
const [output, ofiles] = await this.root.execute("admin.instructors.remove", email)
|
|
3628
|
+
return output
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
|
|
3632
|
+
/**
|
|
3633
|
+
*
|
|
3634
|
+
* No description yet
|
|
3635
|
+
*
|
|
3636
|
+
*/
|
|
3637
|
+
class Module_admin_users {
|
|
3638
|
+
private readonly root: JutgeApiClient
|
|
3639
|
+
|
|
3640
|
+
constructor(root: JutgeApiClient) {
|
|
3641
|
+
this.root = root
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
/**
|
|
3645
|
+
* Count users
|
|
3646
|
+
*
|
|
3647
|
+
* 🔐 Authentication: admin
|
|
3648
|
+
* No warnings
|
|
3649
|
+
*
|
|
3650
|
+
*/
|
|
3651
|
+
async count(): Promise<number> {
|
|
3652
|
+
const [output, ofiles] = await this.root.execute("admin.users.count", null)
|
|
3653
|
+
return output
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
/**
|
|
3657
|
+
* Create a user
|
|
3658
|
+
*
|
|
3659
|
+
* 🔐 Authentication: admin
|
|
3660
|
+
* No warnings
|
|
3661
|
+
*
|
|
3662
|
+
*/
|
|
3663
|
+
async create(data: UserCreation): Promise<void> {
|
|
3664
|
+
const [output, ofiles] = await this.root.execute("admin.users.create", data)
|
|
3665
|
+
return output
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
/**
|
|
3669
|
+
* Remove a user
|
|
3670
|
+
*
|
|
3671
|
+
* 🔐 Authentication: admin
|
|
3672
|
+
* No warnings
|
|
3673
|
+
*
|
|
3674
|
+
*/
|
|
3675
|
+
async remove(email: string): Promise<void> {
|
|
3676
|
+
const [output, ofiles] = await this.root.execute("admin.users.remove", email)
|
|
3677
|
+
return output
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3680
|
+
/**
|
|
3681
|
+
* Set a password for a user
|
|
3682
|
+
*
|
|
3683
|
+
* 🔐 Authentication: admin
|
|
3684
|
+
* No warnings
|
|
3685
|
+
*
|
|
3686
|
+
*/
|
|
3687
|
+
async setPassword(data: { email: string; password: string; message: string }): Promise<void> {
|
|
3688
|
+
const [output, ofiles] = await this.root.execute("admin.users.setPassword", data)
|
|
3689
|
+
return output
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3692
|
+
/**
|
|
3693
|
+
* Get all profiles of users whose email or name contains a specific string
|
|
3694
|
+
*
|
|
3695
|
+
* 🔐 Authentication: admin
|
|
3696
|
+
* No warnings
|
|
3697
|
+
*
|
|
3698
|
+
*/
|
|
3699
|
+
async getProfiles(data: string): Promise<ProfileForAdmin[]> {
|
|
3700
|
+
const [output, ofiles] = await this.root.execute("admin.users.getProfiles", data)
|
|
3701
|
+
return output
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
/**
|
|
3705
|
+
* Get all users (well, just email and name) whose email contains a specific string
|
|
3706
|
+
*
|
|
3707
|
+
* 🔐 Authentication: admin
|
|
3708
|
+
* No warnings
|
|
3709
|
+
*
|
|
3710
|
+
*/
|
|
3711
|
+
async getAllWithEmail(data: string): Promise<UsersEmailsAndNames> {
|
|
3712
|
+
const [output, ofiles] = await this.root.execute("admin.users.getAllWithEmail", data)
|
|
3713
|
+
return output
|
|
3714
|
+
}
|
|
3715
|
+
|
|
3716
|
+
/**
|
|
3717
|
+
* Get a list of emails of spam users
|
|
3718
|
+
*
|
|
3719
|
+
* 🔐 Authentication: admin
|
|
3720
|
+
* No warnings
|
|
3721
|
+
*
|
|
3722
|
+
*/
|
|
3723
|
+
async getSpamUsers(): Promise<string[]> {
|
|
3724
|
+
const [output, ofiles] = await this.root.execute("admin.users.getSpamUsers", null)
|
|
3725
|
+
return output
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
/**
|
|
3729
|
+
* Remove spam users
|
|
3730
|
+
*
|
|
3731
|
+
* 🔐 Authentication: admin
|
|
3732
|
+
* No warnings
|
|
3733
|
+
*
|
|
3734
|
+
*/
|
|
3735
|
+
async removeSpamUsers(data: string[]): Promise<void> {
|
|
3736
|
+
const [output, ofiles] = await this.root.execute("admin.users.removeSpamUsers", data)
|
|
3737
|
+
return output
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
/**
|
|
3742
|
+
*
|
|
3743
|
+
* No description yet
|
|
3744
|
+
*
|
|
3745
|
+
*/
|
|
3746
|
+
class Module_admin_dashboard {
|
|
3747
|
+
private readonly root: JutgeApiClient
|
|
3748
|
+
|
|
3749
|
+
constructor(root: JutgeApiClient) {
|
|
3750
|
+
this.root = root
|
|
3751
|
+
}
|
|
3752
|
+
|
|
3753
|
+
/**
|
|
3754
|
+
* Get all admin dashboard items.
|
|
3755
|
+
*
|
|
3756
|
+
* 🔐 Authentication: admin
|
|
3757
|
+
* No warnings
|
|
3758
|
+
*
|
|
3759
|
+
*/
|
|
3760
|
+
async getAll(): Promise<AdminDashboard> {
|
|
3761
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getAll", null)
|
|
3762
|
+
return output
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
/**
|
|
3766
|
+
* Get database info.
|
|
3767
|
+
*
|
|
3768
|
+
* 🔐 Authentication: admin
|
|
3769
|
+
* No warnings
|
|
3770
|
+
*
|
|
3771
|
+
*/
|
|
3772
|
+
async getDatabasesInfo(): Promise<DatabasesInfo> {
|
|
3773
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getDatabasesInfo", null)
|
|
3774
|
+
return output
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3777
|
+
/**
|
|
3778
|
+
* Get free disk space.
|
|
3779
|
+
*
|
|
3780
|
+
* 🔐 Authentication: admin
|
|
3781
|
+
* No warnings
|
|
3782
|
+
*
|
|
3783
|
+
*/
|
|
3784
|
+
async getFreeDiskSpace(): Promise<FreeDiskSpace> {
|
|
3785
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getFreeDiskSpace", null)
|
|
3786
|
+
return output
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3789
|
+
/**
|
|
3790
|
+
* Get recent connected users.
|
|
3791
|
+
*
|
|
3792
|
+
* 🔐 Authentication: admin
|
|
3793
|
+
* No warnings
|
|
3794
|
+
*
|
|
3795
|
+
*/
|
|
3796
|
+
async getRecentConnectedUsers(): Promise<RecentConnectedUsers> {
|
|
3797
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getRecentConnectedUsers", null)
|
|
3798
|
+
return output
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3801
|
+
/**
|
|
3802
|
+
* Get recent load averages.
|
|
3803
|
+
*
|
|
3804
|
+
* 🔐 Authentication: admin
|
|
3805
|
+
* No warnings
|
|
3806
|
+
*
|
|
3807
|
+
*/
|
|
3808
|
+
async getRecentLoadAverages(): Promise<RecentLoadAverages> {
|
|
3809
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getRecentLoadAverages", null)
|
|
3810
|
+
return output
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
/**
|
|
3814
|
+
* Get recent submissions.
|
|
3815
|
+
*
|
|
3816
|
+
* 🔐 Authentication: admin
|
|
3817
|
+
* No warnings
|
|
3818
|
+
*
|
|
3819
|
+
*/
|
|
3820
|
+
async getRecentSubmissions(): Promise<RecentSubmissions> {
|
|
3821
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getRecentSubmissions", null)
|
|
3822
|
+
return output
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
/**
|
|
3826
|
+
* Get submissions histograms.
|
|
3827
|
+
*
|
|
3828
|
+
* 🔐 Authentication: admin
|
|
3829
|
+
* No warnings
|
|
3830
|
+
*
|
|
3831
|
+
*/
|
|
3832
|
+
async getSubmissionsHistograms(): Promise<SubmissionsHistograms> {
|
|
3833
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getSubmissionsHistograms", null)
|
|
3834
|
+
return output
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
/**
|
|
3838
|
+
* Get zombies.
|
|
3839
|
+
*
|
|
3840
|
+
* 🔐 Authentication: admin
|
|
3841
|
+
* No warnings
|
|
3842
|
+
*
|
|
3843
|
+
*/
|
|
3844
|
+
async getZombies(): Promise<Zombies> {
|
|
3845
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getZombies", null)
|
|
3846
|
+
return output
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3849
|
+
/**
|
|
3850
|
+
* Get upcoming exams
|
|
3851
|
+
*
|
|
3852
|
+
* 🔐 Authentication: admin
|
|
3853
|
+
* No warnings
|
|
3854
|
+
*
|
|
3855
|
+
*/
|
|
3856
|
+
async getUpcomingExams(data: { daysBefore: number; daysAfter: number }): Promise<UpcomingExams> {
|
|
3857
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getUpcomingExams", data)
|
|
3858
|
+
return output
|
|
3859
|
+
}
|
|
3860
|
+
|
|
3861
|
+
/**
|
|
3862
|
+
* Get pm2 status
|
|
3863
|
+
*
|
|
3864
|
+
* 🔐 Authentication: admin
|
|
3865
|
+
* No warnings
|
|
3866
|
+
* This endpoint retrieves the status of PM2 processes as reported by `pm2 jlist`.
|
|
3867
|
+
*/
|
|
3868
|
+
async getPM2Status(): Promise<any> {
|
|
3869
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getPM2Status", null)
|
|
3870
|
+
return output
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3873
|
+
/**
|
|
3874
|
+
* Get docker status
|
|
3875
|
+
*
|
|
3876
|
+
* 🔐 Authentication: admin
|
|
3877
|
+
* No warnings
|
|
3878
|
+
* This endpoint retrieves the status of docker processes as reported by `docker ps --all`.
|
|
3879
|
+
*/
|
|
3880
|
+
async getDockerStatus(): Promise<any> {
|
|
3881
|
+
const [output, ofiles] = await this.root.execute("admin.dashboard.getDockerStatus", null)
|
|
3882
|
+
return output
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
/**
|
|
3887
|
+
*
|
|
3888
|
+
* No description yet
|
|
3889
|
+
*
|
|
3890
|
+
*/
|
|
3891
|
+
class Module_admin_queue {
|
|
3892
|
+
private readonly root: JutgeApiClient
|
|
3893
|
+
|
|
3894
|
+
constructor(root: JutgeApiClient) {
|
|
3895
|
+
this.root = root
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
/**
|
|
3899
|
+
* Get the lattest submissions from the queue in descending chronological order for a certain verdict.
|
|
3900
|
+
*
|
|
3901
|
+
* 🔐 Authentication: admin
|
|
3902
|
+
* No warnings
|
|
3903
|
+
* The `limit` parameter tells the number of submissions to retrieve. The `verdicts` parameter is an array of verdicts to filter the submissions. If no verdicts are provided, all submissions will be retrieved.
|
|
3904
|
+
*/
|
|
3905
|
+
async getQueue(data: QueueQuery): Promise<SubmissionQueueItems> {
|
|
3906
|
+
const [output, ofiles] = await this.root.execute("admin.queue.getQueue", data)
|
|
3907
|
+
return output
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
|
|
3911
|
+
/**
|
|
3912
|
+
*
|
|
3913
|
+
* No description yet
|
|
3914
|
+
*
|
|
3915
|
+
*/
|
|
3916
|
+
class Module_admin_tasks {
|
|
3917
|
+
private readonly root: JutgeApiClient
|
|
3918
|
+
|
|
3919
|
+
constructor(root: JutgeApiClient) {
|
|
3920
|
+
this.root = root
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
/**
|
|
3924
|
+
* Purge expired access tokens.
|
|
3925
|
+
*
|
|
3926
|
+
* 🔐 Authentication: admin
|
|
3927
|
+
* No warnings
|
|
3928
|
+
* Purge expired access tokens (call it from time to time, it does not hurt)
|
|
3929
|
+
*/
|
|
3930
|
+
async purgeAuthTokens(): Promise<void> {
|
|
3931
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.purgeAuthTokens", null)
|
|
3932
|
+
return output
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3935
|
+
/**
|
|
3936
|
+
* Clear all memoization caches.
|
|
3937
|
+
*
|
|
3938
|
+
* 🔐 Authentication: admin
|
|
3939
|
+
* No warnings
|
|
3940
|
+
*
|
|
3941
|
+
*/
|
|
3942
|
+
async clearCaches(): Promise<void> {
|
|
3943
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.clearCaches", null)
|
|
3944
|
+
return output
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3947
|
+
/**
|
|
3948
|
+
* Fatalize IE submissions.
|
|
3949
|
+
*
|
|
3950
|
+
* 🔐 Authentication: admin
|
|
3951
|
+
* No warnings
|
|
3952
|
+
*
|
|
3953
|
+
*/
|
|
3954
|
+
async fatalizeIEs(): Promise<void> {
|
|
3955
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.fatalizeIEs", null)
|
|
3956
|
+
return output
|
|
3957
|
+
}
|
|
3958
|
+
|
|
3959
|
+
/**
|
|
3960
|
+
* Fatalize pending submissions.
|
|
3961
|
+
*
|
|
3962
|
+
* 🔐 Authentication: admin
|
|
3963
|
+
* No warnings
|
|
3964
|
+
*
|
|
3965
|
+
*/
|
|
3966
|
+
async fatalizePendings(): Promise<void> {
|
|
3967
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.fatalizePendings", null)
|
|
3968
|
+
return output
|
|
3969
|
+
}
|
|
3970
|
+
|
|
3971
|
+
/**
|
|
3972
|
+
* Resubmit IE submissions.
|
|
3973
|
+
*
|
|
3974
|
+
* 🔐 Authentication: admin
|
|
3975
|
+
* No warnings
|
|
3976
|
+
*
|
|
3977
|
+
*/
|
|
3978
|
+
async resubmitIEs(): Promise<void> {
|
|
3979
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.resubmitIEs", null)
|
|
3980
|
+
return output
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3983
|
+
/**
|
|
3984
|
+
* Resubmit pending submissions.
|
|
3985
|
+
*
|
|
3986
|
+
* 🔐 Authentication: admin
|
|
3987
|
+
* No warnings
|
|
3988
|
+
*
|
|
3989
|
+
*/
|
|
3990
|
+
async resubmitPendings(): Promise<void> {
|
|
3991
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.resubmitPendings", null)
|
|
3992
|
+
return output
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3995
|
+
/**
|
|
3996
|
+
* Get full text search database status.
|
|
3997
|
+
*
|
|
3998
|
+
* 🔐 Authentication: admin
|
|
3999
|
+
* No warnings
|
|
4000
|
+
*
|
|
4001
|
+
*/
|
|
4002
|
+
async getFullTextSearchDatabase(): Promise<Download> {
|
|
4003
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.getFullTextSearchDatabase", null)
|
|
4004
|
+
return ofiles[0]
|
|
4005
|
+
}
|
|
4006
|
+
|
|
4007
|
+
/**
|
|
4008
|
+
* Update semantic search database.
|
|
4009
|
+
*
|
|
4010
|
+
* 🔐 Authentication: admin
|
|
4011
|
+
* No warnings
|
|
4012
|
+
*
|
|
4013
|
+
*/
|
|
4014
|
+
async updateSemanticSearchDatabase(data: string, ifile: File): Promise<void> {
|
|
4015
|
+
const [output, ofiles] = await this.root.execute("admin.tasks.updateSemanticSearchDatabase", data, [ifile])
|
|
4016
|
+
return output
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
|
|
4020
|
+
/**
|
|
4021
|
+
*
|
|
4022
|
+
* No description yet
|
|
4023
|
+
*
|
|
4024
|
+
*/
|
|
4025
|
+
class Module_admin_stats {
|
|
4026
|
+
private readonly root: JutgeApiClient
|
|
4027
|
+
|
|
4028
|
+
constructor(root: JutgeApiClient) {
|
|
4029
|
+
this.root = root
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4032
|
+
/**
|
|
4033
|
+
* Get counters.
|
|
4034
|
+
*
|
|
4035
|
+
* 🔐 Authentication: admin
|
|
4036
|
+
* No warnings
|
|
4037
|
+
*
|
|
4038
|
+
*/
|
|
4039
|
+
async getCounters(): Promise<Record<string, number>> {
|
|
4040
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getCounters", null)
|
|
4041
|
+
return output
|
|
4042
|
+
}
|
|
4043
|
+
|
|
4044
|
+
/**
|
|
4045
|
+
* Get distribution of verdicts.
|
|
4046
|
+
*
|
|
4047
|
+
* 🔐 Authentication: admin
|
|
4048
|
+
* No warnings
|
|
4049
|
+
*
|
|
4050
|
+
*/
|
|
4051
|
+
async getDistributionOfVerdicts(): Promise<Record<string, number>> {
|
|
4052
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfVerdicts", null)
|
|
4053
|
+
return output
|
|
4054
|
+
}
|
|
4055
|
+
|
|
4056
|
+
/**
|
|
4057
|
+
* Get distribution of verdicts by year.
|
|
4058
|
+
*
|
|
4059
|
+
* 🔐 Authentication: admin
|
|
4060
|
+
* No warnings
|
|
4061
|
+
*
|
|
4062
|
+
*/
|
|
4063
|
+
async getDistributionOfVerdictsByYear(): Promise<Record<string, number>[]> {
|
|
4064
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfVerdictsByYear", null)
|
|
4065
|
+
return output
|
|
4066
|
+
}
|
|
4067
|
+
|
|
4068
|
+
/**
|
|
4069
|
+
* Get distribution of compilers.
|
|
4070
|
+
*
|
|
4071
|
+
* 🔐 Authentication: admin
|
|
4072
|
+
* No warnings
|
|
4073
|
+
*
|
|
4074
|
+
*/
|
|
4075
|
+
async getDistributionOfCompilers(): Promise<Record<string, number>> {
|
|
4076
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfCompilers", null)
|
|
4077
|
+
return output
|
|
4078
|
+
}
|
|
4079
|
+
|
|
4080
|
+
/**
|
|
4081
|
+
* Get distribution of proglangs.
|
|
4082
|
+
*
|
|
4083
|
+
* 🔐 Authentication: admin
|
|
4084
|
+
* No warnings
|
|
4085
|
+
*
|
|
4086
|
+
*/
|
|
4087
|
+
async getDistributionOfProglangs(): Promise<Record<string, number>> {
|
|
4088
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfProglangs", null)
|
|
4089
|
+
return output
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
/**
|
|
4093
|
+
* Get distribution of registered users by year.
|
|
4094
|
+
*
|
|
4095
|
+
* 🔐 Authentication: admin
|
|
4096
|
+
* No warnings
|
|
4097
|
+
*
|
|
4098
|
+
*/
|
|
4099
|
+
async getDistributionOfUsersByYear(): Promise<Record<string, number>> {
|
|
4100
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfUsersByYear", null)
|
|
4101
|
+
return output
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
/**
|
|
4105
|
+
* Get distribution of registered users by country.
|
|
4106
|
+
*
|
|
4107
|
+
* 🔐 Authentication: admin
|
|
4108
|
+
* No warnings
|
|
4109
|
+
*
|
|
4110
|
+
*/
|
|
4111
|
+
async getDistributionOfUsersByCountry(): Promise<Record<string, number>> {
|
|
4112
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfUsersByCountry", null)
|
|
4113
|
+
return output
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4116
|
+
/**
|
|
4117
|
+
* Get distribution of registered users by submissions using a custom bucket size.
|
|
4118
|
+
*
|
|
4119
|
+
* 🔐 Authentication: admin
|
|
4120
|
+
* No warnings
|
|
4121
|
+
*
|
|
4122
|
+
*/
|
|
4123
|
+
async getDistributionOfUsersBySubmissions(data: number): Promise<Record<string, number>> {
|
|
4124
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfUsersBySubmissions", data)
|
|
4125
|
+
return output
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
/**
|
|
4129
|
+
* Get ranking of users.
|
|
4130
|
+
*
|
|
4131
|
+
* 🔐 Authentication: admin
|
|
4132
|
+
* ❌ Warning: Input type is not correct
|
|
4133
|
+
*
|
|
4134
|
+
*/
|
|
4135
|
+
async getRankingOfUsers(limit: number): Promise<UserRanking> {
|
|
4136
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getRankingOfUsers", limit)
|
|
4137
|
+
return output
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
/**
|
|
4141
|
+
* Get distribution of submissions by hour.
|
|
4142
|
+
*
|
|
4143
|
+
* 🔐 Authentication: admin
|
|
4144
|
+
* No warnings
|
|
4145
|
+
*
|
|
4146
|
+
*/
|
|
4147
|
+
async getDistributionOfSubmissionsByHour(): Promise<Record<string, number>> {
|
|
4148
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfSubmissionsByHour", null)
|
|
4149
|
+
return output
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
/**
|
|
4153
|
+
* Get distribution of submissions by proglang.
|
|
4154
|
+
*
|
|
4155
|
+
* 🔐 Authentication: admin
|
|
4156
|
+
* No warnings
|
|
4157
|
+
*
|
|
4158
|
+
*/
|
|
4159
|
+
async getDistributionOfSubmissionsByProglang(): Promise<Record<string, number>> {
|
|
4160
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfSubmissionsByProglang", null)
|
|
4161
|
+
return output
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
/**
|
|
4165
|
+
* Get distribution of submissions by compiler.
|
|
4166
|
+
*
|
|
4167
|
+
* 🔐 Authentication: admin
|
|
4168
|
+
* No warnings
|
|
4169
|
+
*
|
|
4170
|
+
*/
|
|
4171
|
+
async getDistributionOfSubmissionsByCompiler(): Promise<Record<string, number>> {
|
|
4172
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfSubmissionsByCompiler", null)
|
|
4173
|
+
return output
|
|
4174
|
+
}
|
|
4175
|
+
|
|
4176
|
+
/**
|
|
4177
|
+
* Get distribution of submissions by weekday.
|
|
4178
|
+
*
|
|
4179
|
+
* 🔐 Authentication: admin
|
|
4180
|
+
* No warnings
|
|
4181
|
+
*
|
|
4182
|
+
*/
|
|
4183
|
+
async getDistributionOfSubmissionsByWeekday(): Promise<Record<string, number>> {
|
|
4184
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfSubmissionsByWeekday", null)
|
|
4185
|
+
return output
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
/**
|
|
4189
|
+
* Get distribution of submissions by year.
|
|
4190
|
+
*
|
|
4191
|
+
* 🔐 Authentication: admin
|
|
4192
|
+
* No warnings
|
|
4193
|
+
*
|
|
4194
|
+
*/
|
|
4195
|
+
async getDistributionOfSubmissionsByYear(): Promise<Record<string, number>> {
|
|
4196
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfSubmissionsByYear", null)
|
|
4197
|
+
return output
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
/**
|
|
4201
|
+
* Get distribution of submissions by year for a proglang.
|
|
4202
|
+
*
|
|
4203
|
+
* 🔐 Authentication: admin
|
|
4204
|
+
* No warnings
|
|
4205
|
+
*
|
|
4206
|
+
*/
|
|
4207
|
+
async getDistributionOfSubmissionsByYearForProglang(proglang: string): Promise<Record<string, number>> {
|
|
4208
|
+
const [output, ofiles] = await this.root.execute(
|
|
4209
|
+
"admin.stats.getDistributionOfSubmissionsByYearForProglang",
|
|
4210
|
+
proglang,
|
|
4211
|
+
)
|
|
4212
|
+
return output
|
|
4213
|
+
}
|
|
4214
|
+
|
|
4215
|
+
/**
|
|
4216
|
+
* Get distribution of submissions by day.
|
|
4217
|
+
*
|
|
4218
|
+
* 🔐 Authentication: admin
|
|
4219
|
+
* No warnings
|
|
4220
|
+
*
|
|
4221
|
+
*/
|
|
4222
|
+
async getDistributionOfSubmissionsByDay(): Promise<Record<string, number>> {
|
|
4223
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfSubmissionsByDay", null)
|
|
4224
|
+
return output
|
|
4225
|
+
}
|
|
4226
|
+
|
|
4227
|
+
/**
|
|
4228
|
+
* Get heatmap calendar of submissions.
|
|
4229
|
+
*
|
|
4230
|
+
* 🔐 Authentication: admin
|
|
4231
|
+
* No warnings
|
|
4232
|
+
*
|
|
4233
|
+
*/
|
|
4234
|
+
async getHeatmapCalendarOfSubmissions(data: DateRange): Promise<any> {
|
|
4235
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getHeatmapCalendarOfSubmissions", data)
|
|
4236
|
+
return output
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
/**
|
|
4240
|
+
* Get distribution of domains of users' emails.
|
|
4241
|
+
*
|
|
4242
|
+
* 🔐 Authentication: admin
|
|
4243
|
+
* No warnings
|
|
4244
|
+
*
|
|
4245
|
+
*/
|
|
4246
|
+
async getDistributionOfDomains(): Promise<Record<string, number>> {
|
|
4247
|
+
const [output, ofiles] = await this.root.execute("admin.stats.getDistributionOfDomains", null)
|
|
4248
|
+
return output
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
|
|
4252
|
+
/**
|
|
4253
|
+
*
|
|
4254
|
+
* No description yet
|
|
4255
|
+
*
|
|
4256
|
+
*/
|
|
4257
|
+
class Module_admin_problems {
|
|
4258
|
+
private readonly root: JutgeApiClient
|
|
4259
|
+
|
|
4260
|
+
constructor(root: JutgeApiClient) {
|
|
4261
|
+
this.root = root
|
|
4262
|
+
}
|
|
4263
|
+
|
|
4264
|
+
/**
|
|
4265
|
+
* Get list of proglangs for which the problem has an official solution.
|
|
4266
|
+
*
|
|
4267
|
+
* 🔐 Authentication: admin
|
|
4268
|
+
* No warnings
|
|
4269
|
+
*
|
|
4270
|
+
*/
|
|
4271
|
+
async getSolutions(problem_id: string): Promise<string[]> {
|
|
4272
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getSolutions", problem_id)
|
|
4273
|
+
return output
|
|
4274
|
+
}
|
|
4275
|
+
|
|
4276
|
+
/**
|
|
4277
|
+
* Get official solution for a problem in proglang as a string in base64.
|
|
4278
|
+
*
|
|
4279
|
+
* 🔐 Authentication: admin
|
|
4280
|
+
* No warnings
|
|
4281
|
+
*
|
|
4282
|
+
*/
|
|
4283
|
+
async getSolutionAsB64(data: { problem_id: string; proglang: string }): Promise<string> {
|
|
4284
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getSolutionAsB64", data)
|
|
4285
|
+
return output
|
|
4286
|
+
}
|
|
4287
|
+
|
|
4288
|
+
/**
|
|
4289
|
+
* Get official solution for a problem in proglang as a file.
|
|
4290
|
+
*
|
|
4291
|
+
* 🔐 Authentication: admin
|
|
4292
|
+
* No warnings
|
|
4293
|
+
*
|
|
4294
|
+
*/
|
|
4295
|
+
async getSolutionAsFile(data: { problem_id: string; proglang: string }): Promise<Download> {
|
|
4296
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getSolutionAsFile", data)
|
|
4297
|
+
return ofiles[0]
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
/**
|
|
4301
|
+
* Prepare summary for a problem.
|
|
4302
|
+
*
|
|
4303
|
+
* 🔐 Authentication: admin
|
|
4304
|
+
* No warnings
|
|
4305
|
+
*
|
|
4306
|
+
*/
|
|
4307
|
+
async prepareProblemSummary(data: { problem_id: string; model: string }): Promise<ProblemSummary> {
|
|
4308
|
+
const [output, ofiles] = await this.root.execute("admin.problems.prepareProblemSummary", data)
|
|
4309
|
+
return output
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4312
|
+
/**
|
|
4313
|
+
* Get summary for a problem.
|
|
4314
|
+
*
|
|
4315
|
+
* 🔐 Authentication: admin
|
|
4316
|
+
* No warnings
|
|
4317
|
+
*
|
|
4318
|
+
*/
|
|
4319
|
+
async getProblemSummary(problem_id: string): Promise<ProblemSummary | null> {
|
|
4320
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getProblemSummary", problem_id)
|
|
4321
|
+
return output
|
|
4322
|
+
}
|
|
4323
|
+
|
|
4324
|
+
/**
|
|
4325
|
+
* Get list of problems with summary.
|
|
4326
|
+
*
|
|
4327
|
+
* 🔐 Authentication: admin
|
|
4328
|
+
* No warnings
|
|
4329
|
+
*
|
|
4330
|
+
*/
|
|
4331
|
+
async getProblemsWithSummary(): Promise<string[]> {
|
|
4332
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getProblemsWithSummary", null)
|
|
4333
|
+
return output
|
|
4334
|
+
}
|
|
4335
|
+
|
|
4336
|
+
/**
|
|
4337
|
+
* Get list of problems without summary.
|
|
4338
|
+
*
|
|
4339
|
+
* 🔐 Authentication: admin
|
|
4340
|
+
* No warnings
|
|
4341
|
+
*
|
|
4342
|
+
*/
|
|
4343
|
+
async getProblemsWithoutSummary(): Promise<string[]> {
|
|
4344
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getProblemsWithoutSummary", null)
|
|
4345
|
+
return output
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
/**
|
|
4349
|
+
* Prepare solution tags for an abstract problem.
|
|
4350
|
+
*
|
|
4351
|
+
* 🔐 Authentication: admin
|
|
4352
|
+
* No warnings
|
|
4353
|
+
*
|
|
4354
|
+
*/
|
|
4355
|
+
async prepareAbstractProblemSolutionTags(data: { problem_nm: string; model: string }): Promise<SolutionTags> {
|
|
4356
|
+
const [output, ofiles] = await this.root.execute("admin.problems.prepareAbstractProblemSolutionTags", data)
|
|
4357
|
+
return output
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
/**
|
|
4361
|
+
* Get solution tags for an abstract problem.
|
|
4362
|
+
*
|
|
4363
|
+
* 🔐 Authentication: admin
|
|
4364
|
+
* No warnings
|
|
4365
|
+
*
|
|
4366
|
+
*/
|
|
4367
|
+
async getAbstractProblemSolutionTags(data: { problem_nm: string }): Promise<SolutionTags | null> {
|
|
4368
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getAbstractProblemSolutionTags", data)
|
|
4369
|
+
return output
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
/**
|
|
4373
|
+
* Get list of abstract problems with solution tags.
|
|
4374
|
+
*
|
|
4375
|
+
* 🔐 Authentication: admin
|
|
4376
|
+
* No warnings
|
|
4377
|
+
*
|
|
4378
|
+
*/
|
|
4379
|
+
async getAbstractProblemsWithSolutionTags(): Promise<string[]> {
|
|
4380
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getAbstractProblemsWithSolutionTags", null)
|
|
4381
|
+
return output
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4384
|
+
/**
|
|
4385
|
+
* Get list of abstract problems without solution tags.
|
|
4386
|
+
*
|
|
4387
|
+
* 🔐 Authentication: admin
|
|
4388
|
+
* No warnings
|
|
4389
|
+
*
|
|
4390
|
+
*/
|
|
4391
|
+
async getAbstractProblemsWithoutSolutionTags(): Promise<string[]> {
|
|
4392
|
+
const [output, ofiles] = await this.root.execute("admin.problems.getAbstractProblemsWithoutSolutionTags", null)
|
|
4393
|
+
return output
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
/**
|
|
4398
|
+
*
|
|
4399
|
+
* Module with testing endpoints. Not meant for regular users.
|
|
4400
|
+
*
|
|
4401
|
+
*/
|
|
4402
|
+
class Module_testing {
|
|
4403
|
+
private readonly root: JutgeApiClient
|
|
4404
|
+
|
|
4405
|
+
readonly check: Module_testing_check
|
|
4406
|
+
readonly playground: Module_testing_playground
|
|
4407
|
+
|
|
4408
|
+
constructor(root: JutgeApiClient) {
|
|
4409
|
+
this.root = root
|
|
4410
|
+
this.check = new Module_testing_check(root)
|
|
4411
|
+
this.playground = new Module_testing_playground(root)
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4415
|
+
/**
|
|
4416
|
+
*
|
|
4417
|
+
* This module is intended for internal use and contains functions to check the actor of the query. General public should not rely on it.
|
|
4418
|
+
*
|
|
4419
|
+
*/
|
|
4420
|
+
class Module_testing_check {
|
|
4421
|
+
private readonly root: JutgeApiClient
|
|
4422
|
+
|
|
4423
|
+
constructor(root: JutgeApiClient) {
|
|
4424
|
+
this.root = root
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4427
|
+
/**
|
|
4428
|
+
* Checks that query actor is a user.
|
|
4429
|
+
*
|
|
4430
|
+
* 🔐 Authentication: user
|
|
4431
|
+
* No warnings
|
|
4432
|
+
*
|
|
4433
|
+
*/
|
|
4434
|
+
async checkUser(): Promise<void> {
|
|
4435
|
+
const [output, ofiles] = await this.root.execute("testing.check.checkUser", null)
|
|
4436
|
+
return output
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
/**
|
|
4440
|
+
* Checks that query actor is an instructor.
|
|
4441
|
+
*
|
|
4442
|
+
* 🔐 Authentication: instructor
|
|
4443
|
+
* No warnings
|
|
4444
|
+
*
|
|
4445
|
+
*/
|
|
4446
|
+
async checkInstructor(): Promise<void> {
|
|
4447
|
+
const [output, ofiles] = await this.root.execute("testing.check.checkInstructor", null)
|
|
4448
|
+
return output
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
/**
|
|
4452
|
+
* Checks that query actor is an admin.
|
|
4453
|
+
*
|
|
4454
|
+
* 🔐 Authentication: admin
|
|
4455
|
+
* No warnings
|
|
4456
|
+
*
|
|
4457
|
+
*/
|
|
4458
|
+
async checkAdmin(): Promise<void> {
|
|
4459
|
+
const [output, ofiles] = await this.root.execute("testing.check.checkAdmin", null)
|
|
4460
|
+
return output
|
|
4461
|
+
}
|
|
4462
|
+
|
|
4463
|
+
/**
|
|
4464
|
+
* Throw an exception of the given type.
|
|
4465
|
+
*
|
|
4466
|
+
* 🔐 Authentication: any
|
|
4467
|
+
* No warnings
|
|
4468
|
+
*
|
|
4469
|
+
*/
|
|
4470
|
+
async throwError(exception: string): Promise<void> {
|
|
4471
|
+
const [output, ofiles] = await this.root.execute("testing.check.throwError", exception)
|
|
4472
|
+
return output
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4476
|
+
/**
|
|
4477
|
+
*
|
|
4478
|
+
* This module is intended for internal use. General users should not rely on it.
|
|
4479
|
+
*
|
|
4480
|
+
*/
|
|
4481
|
+
class Module_testing_playground {
|
|
4482
|
+
private readonly root: JutgeApiClient
|
|
4483
|
+
|
|
4484
|
+
constructor(root: JutgeApiClient) {
|
|
4485
|
+
this.root = root
|
|
4486
|
+
}
|
|
4487
|
+
|
|
4488
|
+
/**
|
|
4489
|
+
* Upload a file.
|
|
4490
|
+
*
|
|
4491
|
+
* 🔐 Authentication: any
|
|
4492
|
+
* No warnings
|
|
4493
|
+
*
|
|
4494
|
+
*/
|
|
4495
|
+
async upload(data: Name, ifile: File): Promise<string> {
|
|
4496
|
+
const [output, ofiles] = await this.root.execute("testing.playground.upload", data, [ifile])
|
|
4497
|
+
return output
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
/**
|
|
4501
|
+
* Get negative of an image.
|
|
4502
|
+
*
|
|
4503
|
+
* 🔐 Authentication: any
|
|
4504
|
+
* No warnings
|
|
4505
|
+
*
|
|
4506
|
+
*/
|
|
4507
|
+
async negate(ifile: File): Promise<Download> {
|
|
4508
|
+
const [output, ofiles] = await this.root.execute("testing.playground.negate", null, [ifile])
|
|
4509
|
+
return ofiles[0]
|
|
4510
|
+
}
|
|
4511
|
+
|
|
4512
|
+
/**
|
|
4513
|
+
* Download a file.
|
|
4514
|
+
*
|
|
4515
|
+
* 🔐 Authentication: any
|
|
4516
|
+
* No warnings
|
|
4517
|
+
*
|
|
4518
|
+
*/
|
|
4519
|
+
async download(data: Name): Promise<Download> {
|
|
4520
|
+
const [output, ofiles] = await this.root.execute("testing.playground.download", data)
|
|
4521
|
+
return ofiles[0]
|
|
4522
|
+
}
|
|
4523
|
+
|
|
4524
|
+
/**
|
|
4525
|
+
* Download a file with a string.
|
|
4526
|
+
*
|
|
4527
|
+
* 🔐 Authentication: any
|
|
4528
|
+
* No warnings
|
|
4529
|
+
*
|
|
4530
|
+
*/
|
|
4531
|
+
async download2(data: Name): Promise<[string, Download]> {
|
|
4532
|
+
const [output, ofiles] = await this.root.execute("testing.playground.download2", data)
|
|
4533
|
+
return [output, ofiles[0]]
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4536
|
+
/**
|
|
4537
|
+
* Ping the server to get a pong string.
|
|
4538
|
+
*
|
|
4539
|
+
* 🔐 Authentication: any
|
|
4540
|
+
* No warnings
|
|
4541
|
+
*
|
|
4542
|
+
*/
|
|
4543
|
+
async ping(): Promise<string> {
|
|
4544
|
+
const [output, ofiles] = await this.root.execute("testing.playground.ping", null)
|
|
4545
|
+
return output
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
/**
|
|
4549
|
+
* Returns the given string in uppercase.
|
|
4550
|
+
*
|
|
4551
|
+
* 🔐 Authentication: any
|
|
4552
|
+
* No warnings
|
|
4553
|
+
*
|
|
4554
|
+
*/
|
|
4555
|
+
async toUpperCase(s: string): Promise<string> {
|
|
4556
|
+
const [output, ofiles] = await this.root.execute("testing.playground.toUpperCase", s)
|
|
4557
|
+
return output
|
|
4558
|
+
}
|
|
4559
|
+
|
|
4560
|
+
/**
|
|
4561
|
+
* Returns the sum of two integers.
|
|
4562
|
+
*
|
|
4563
|
+
* 🔐 Authentication: any
|
|
4564
|
+
* No warnings
|
|
4565
|
+
*
|
|
4566
|
+
*/
|
|
4567
|
+
async add2i(data: TwoInts): Promise<number> {
|
|
4568
|
+
const [output, ofiles] = await this.root.execute("testing.playground.add2i", data)
|
|
4569
|
+
return output
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4572
|
+
/**
|
|
4573
|
+
* Returns the sum of two floats.
|
|
4574
|
+
*
|
|
4575
|
+
* 🔐 Authentication: any
|
|
4576
|
+
* No warnings
|
|
4577
|
+
*
|
|
4578
|
+
*/
|
|
4579
|
+
async add2f(data: TwoFloats): Promise<number> {
|
|
4580
|
+
const [output, ofiles] = await this.root.execute("testing.playground.add2f", data)
|
|
4581
|
+
return output
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
/**
|
|
4585
|
+
* increment two numbers.
|
|
4586
|
+
*
|
|
4587
|
+
* 🔐 Authentication: any
|
|
4588
|
+
* No warnings
|
|
4589
|
+
*
|
|
4590
|
+
*/
|
|
4591
|
+
async inc(data: TwoInts): Promise<TwoInts> {
|
|
4592
|
+
const [output, ofiles] = await this.root.execute("testing.playground.inc", data)
|
|
4593
|
+
return output
|
|
4594
|
+
}
|
|
4595
|
+
|
|
4596
|
+
/**
|
|
4597
|
+
* Returns the sum of three integers.
|
|
4598
|
+
*
|
|
4599
|
+
* 🔐 Authentication: any
|
|
4600
|
+
* No warnings
|
|
4601
|
+
*
|
|
4602
|
+
*/
|
|
4603
|
+
async add3i(data: { a: number; b: number; c: number }): Promise<number> {
|
|
4604
|
+
const [output, ofiles] = await this.root.execute("testing.playground.add3i", data)
|
|
4605
|
+
return output
|
|
4606
|
+
}
|
|
4607
|
+
|
|
4608
|
+
/**
|
|
4609
|
+
* Returns a type with defaults.
|
|
4610
|
+
*
|
|
4611
|
+
* 🔐 Authentication: any
|
|
4612
|
+
* No warnings
|
|
4613
|
+
*
|
|
4614
|
+
*/
|
|
4615
|
+
async something(data: SomeType): Promise<SomeType> {
|
|
4616
|
+
const [output, ofiles] = await this.root.execute("testing.playground.something", data)
|
|
4617
|
+
return output
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4620
|
+
/**
|
|
4621
|
+
* Get a webstream with clok data.
|
|
4622
|
+
*
|
|
4623
|
+
* 🔐 Authentication: any
|
|
4624
|
+
* No warnings
|
|
4625
|
+
*
|
|
4626
|
+
*/
|
|
4627
|
+
async clock(): Promise<WebStream> {
|
|
4628
|
+
const [output, ofiles] = await this.root.execute("testing.playground.clock", null)
|
|
4629
|
+
return output
|
|
4630
|
+
}
|
|
4631
|
+
}
|