academe-kit 0.9.6 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1372,6 +1372,68 @@ interface paths {
1372
1372
  patch?: never;
1373
1373
  trace?: never;
1374
1374
  };
1375
+ "/certificates/{userId}/download-all": {
1376
+ parameters: {
1377
+ query?: never;
1378
+ header?: never;
1379
+ path?: never;
1380
+ cookie?: never;
1381
+ };
1382
+ /**
1383
+ * Download all certificates of a user as a single PDF
1384
+ * @description Downloads all certificates of the given user merged into a single PDF file.
1385
+ * Each certificate occupies one page in the resulting file.
1386
+ * PDFs are downloaded from S3 in parallel and merged using pdf-lib.
1387
+ */
1388
+ get: {
1389
+ parameters: {
1390
+ query?: never;
1391
+ header?: never;
1392
+ path: {
1393
+ /** @description ID of the user whose certificates will be downloaded */
1394
+ userId: string;
1395
+ };
1396
+ cookie?: never;
1397
+ };
1398
+ requestBody?: never;
1399
+ responses: {
1400
+ /** @description Merged PDF file containing all user certificates */
1401
+ 200: {
1402
+ headers: {
1403
+ /** @description attachment; filename="Meus-Certificados.pdf" */
1404
+ "Content-Disposition"?: string;
1405
+ [name: string]: unknown;
1406
+ };
1407
+ content: {
1408
+ "application/pdf": string;
1409
+ };
1410
+ };
1411
+ 401: components["responses"]["Unauthorized"];
1412
+ /** @description No certificates found for the user */
1413
+ 404: {
1414
+ headers: {
1415
+ [name: string]: unknown;
1416
+ };
1417
+ content: {
1418
+ "application/json": {
1419
+ /** @example error */
1420
+ status?: string;
1421
+ /** @example No certificates found for this user */
1422
+ message?: string;
1423
+ };
1424
+ };
1425
+ };
1426
+ 500: components["responses"]["ServerError"];
1427
+ };
1428
+ };
1429
+ put?: never;
1430
+ post?: never;
1431
+ delete?: never;
1432
+ options?: never;
1433
+ head?: never;
1434
+ patch?: never;
1435
+ trace?: never;
1436
+ };
1375
1437
  "/certificates": {
1376
1438
  parameters: {
1377
1439
  query?: never;
@@ -1381,13 +1443,24 @@ interface paths {
1381
1443
  };
1382
1444
  /**
1383
1445
  * List all certificates
1384
- * @description Retrieve a list of all certificates in the system.
1446
+ * @description Retrieve a paginated list of all certificates in the system.
1385
1447
  * Each certificate includes course information (id, title, description) when available.
1386
1448
  * Course data is extracted from the related Quiz through QuizAttempt.
1387
1449
  */
1388
1450
  get: {
1389
1451
  parameters: {
1390
- query?: never;
1452
+ query?: {
1453
+ /** @description Filter certificates by user ID */
1454
+ userId?: string;
1455
+ /** @description Search term */
1456
+ search?: components["parameters"]["search"];
1457
+ /** @description Page number */
1458
+ page?: components["parameters"]["page"];
1459
+ /** @description Items per page */
1460
+ limit?: components["parameters"]["limit"];
1461
+ /** @description Whether to include course data in the response (default true). Pass false to skip course lookup. */
1462
+ includeCourse?: boolean;
1463
+ };
1391
1464
  header?: never;
1392
1465
  path?: never;
1393
1466
  cookie?: never;
@@ -1404,6 +1477,16 @@ interface paths {
1404
1477
  /** @example success */
1405
1478
  status?: string;
1406
1479
  data?: components["schemas"]["Certificate"][];
1480
+ meta?: {
1481
+ /** @example 10 */
1482
+ total?: number;
1483
+ /** @example 1 */
1484
+ page?: number;
1485
+ /** @example 10 */
1486
+ limit?: number;
1487
+ /** @example 1 */
1488
+ totalPages?: number;
1489
+ };
1407
1490
  };
1408
1491
  };
1409
1492
  };
@@ -1439,8 +1522,6 @@ interface paths {
1439
1522
  /** @example success */
1440
1523
  status?: string;
1441
1524
  data?: components["schemas"]["Certificate"];
1442
- /** @example Certificate created successfully */
1443
- message?: string;
1444
1525
  };
1445
1526
  };
1446
1527
  };
@@ -1518,18 +1599,11 @@ interface paths {
1518
1599
  requestBody?: never;
1519
1600
  responses: {
1520
1601
  /** @description Certificate deleted successfully */
1521
- 200: {
1602
+ 204: {
1522
1603
  headers: {
1523
1604
  [name: string]: unknown;
1524
1605
  };
1525
- content: {
1526
- "application/json": {
1527
- /** @example success */
1528
- status?: string;
1529
- /** @example Certificate deleted successfully */
1530
- message?: string;
1531
- };
1532
- };
1606
+ content?: never;
1533
1607
  };
1534
1608
  400: components["responses"]["BadRequest"];
1535
1609
  401: components["responses"]["Unauthorized"];
@@ -1569,8 +1643,6 @@ interface paths {
1569
1643
  /** @example success */
1570
1644
  status?: string;
1571
1645
  data?: components["schemas"]["Certificate"];
1572
- /** @example Certificate updated successfully */
1573
- message?: string;
1574
1646
  };
1575
1647
  };
1576
1648
  };
@@ -1582,6 +1654,123 @@ interface paths {
1582
1654
  };
1583
1655
  trace?: never;
1584
1656
  };
1657
+ "/certificates/{id}/download": {
1658
+ parameters: {
1659
+ query?: never;
1660
+ header?: never;
1661
+ path?: never;
1662
+ cookie?: never;
1663
+ };
1664
+ /**
1665
+ * Download certificate PDF
1666
+ * @description Download the PDF of a specific certificate.
1667
+ * Acts as a proxy to download from S3, avoiding CORS issues.
1668
+ * Only the certificate owner can download their certificate.
1669
+ */
1670
+ get: {
1671
+ parameters: {
1672
+ query?: never;
1673
+ header?: never;
1674
+ path: {
1675
+ /** @description Resource ID */
1676
+ id: components["parameters"]["id"];
1677
+ };
1678
+ cookie?: never;
1679
+ };
1680
+ requestBody?: never;
1681
+ responses: {
1682
+ /** @description Certificate PDF file */
1683
+ 200: {
1684
+ headers: {
1685
+ [name: string]: unknown;
1686
+ };
1687
+ content: {
1688
+ "application/pdf": string;
1689
+ };
1690
+ };
1691
+ 401: components["responses"]["Unauthorized"];
1692
+ 403: components["responses"]["Forbidden"];
1693
+ 404: components["responses"]["NotFound"];
1694
+ 500: components["responses"]["ServerError"];
1695
+ };
1696
+ };
1697
+ put?: never;
1698
+ post?: never;
1699
+ delete?: never;
1700
+ options?: never;
1701
+ head?: never;
1702
+ patch?: never;
1703
+ trace?: never;
1704
+ };
1705
+ "/certificates/generate": {
1706
+ parameters: {
1707
+ query?: never;
1708
+ header?: never;
1709
+ path?: never;
1710
+ cookie?: never;
1711
+ };
1712
+ get?: never;
1713
+ put?: never;
1714
+ /**
1715
+ * Generate a certificate PDF server-side
1716
+ * @description Generates a certificate PDF on the server and creates the certificate record.
1717
+ * This eliminates CORS issues by downloading the template image on the server.
1718
+ *
1719
+ * If the user is currently on a journey "course" step whose `courseModuleId`
1720
+ * matches the quiz's course module, that step is auto-completed as part of
1721
+ * this call (best-effort; failures here are silent and do not affect the cert).
1722
+ */
1723
+ post: {
1724
+ parameters: {
1725
+ query?: never;
1726
+ header?: never;
1727
+ path?: never;
1728
+ cookie?: never;
1729
+ };
1730
+ requestBody: {
1731
+ content: {
1732
+ "application/json": components["schemas"]["GenerateCertificateDto"];
1733
+ };
1734
+ };
1735
+ responses: {
1736
+ /** @description Certificate generated and created successfully */
1737
+ 201: {
1738
+ headers: {
1739
+ [name: string]: unknown;
1740
+ };
1741
+ content: {
1742
+ "application/json": {
1743
+ /** @example success */
1744
+ status?: string;
1745
+ data?: {
1746
+ certificate?: components["schemas"]["Certificate"];
1747
+ /** @example https://s3.amazonaws.com/bucket/certificate.pdf */
1748
+ pdfUrl?: string;
1749
+ /**
1750
+ * @description True when this generation also concluded the user's current journey "course" step
1751
+ * @example true
1752
+ */
1753
+ stepCompleted?: boolean;
1754
+ /**
1755
+ * Format: uuid
1756
+ * @description ID of the challenge_step that was auto-completed, or null when no step was matched
1757
+ */
1758
+ challengeStepId?: string | null;
1759
+ };
1760
+ };
1761
+ };
1762
+ };
1763
+ 400: components["responses"]["BadRequest"];
1764
+ 401: components["responses"]["Unauthorized"];
1765
+ 500: components["responses"]["ServerError"];
1766
+ };
1767
+ };
1768
+ delete?: never;
1769
+ options?: never;
1770
+ head?: never;
1771
+ patch?: never;
1772
+ trace?: never;
1773
+ };
1585
1774
  "/challenge-groups": {
1586
1775
  parameters: {
1587
1776
  query?: never;
@@ -11447,7 +11636,7 @@ interface paths {
11447
11636
  /**
11448
11637
  * Create new submission attempt
11449
11638
  * @description Creates a submission with status=submitted. Validations:
11450
- * - Cannot submit to a global template (clone first)
11639
+ * - institutionId is sent by the client (user's institution_registration), not derived from the challenge
11451
11640
  * - For group challenges: groupId is required and user must be a member
11452
11641
  * - For individual challenges: groupId must be omitted
11453
11642
  * - Cannot create when there is already an active submission (submitted/ai_evaluated)
@@ -11467,6 +11656,11 @@ interface paths {
11467
11656
  "application/json": {
11468
11657
  /** Format: uuid */
11469
11658
  challengeId: string;
11659
+ /**
11660
+ * Format: uuid
11661
+ * @description Institution the user is submitting under (from institution_registration)
11662
+ */
11663
+ institutionId: string;
11470
11664
  /**
11471
11665
  * Format: uuid
11472
11666
  * @description Required when challenge.isGroup=true
@@ -12463,7 +12657,7 @@ interface paths {
12463
12657
  patch?: never;
12464
12658
  trace?: never;
12465
12659
  };
12466
- "/users/me": {
12660
+ "/users-course-log/me/courses/{courseId}/progress": {
12467
12661
  parameters: {
12468
12662
  query?: never;
12469
12663
  header?: never;
@@ -12471,27 +12665,22 @@ interface paths {
12471
12665
  cookie?: never;
12472
12666
  };
12473
12667
  /**
12474
- * Get current authenticated user
12475
- * @description Returns the profile information of the currently authenticated user including:
12476
- * - User groups (userGroups)
12477
- * - User guardians (userGuardians)
12478
- * - Certificates (certificates)
12479
- * - Institution registrations with detailed classroom information (institutionRegistrations)
12480
- * - Institution data
12481
- * - Classroom assignment (institutionClassroom)
12482
- * - Classroom details (name, shift, serie)
12483
- * - Address information (address)
12668
+ * Get authenticated user's progress in a course
12669
+ * @description Returns completed/total active lessons (across every active module of the course)
12670
+ * and a percentage based on `users_course_log` completion events.
12484
12671
  */
12485
12672
  get: {
12486
12673
  parameters: {
12487
12674
  query?: never;
12488
12675
  header?: never;
12489
- path?: never;
12676
+ path: {
12677
+ courseId: string;
12678
+ };
12490
12679
  cookie?: never;
12491
12680
  };
12492
12681
  requestBody?: never;
12493
12682
  responses: {
12494
- /** @description Current user information with all related entities */
12683
+ /** @description Course progress snapshot */
12495
12684
  200: {
12496
12685
  headers: {
12497
12686
  [name: string]: unknown;
@@ -12500,62 +12689,164 @@ interface paths {
12500
12689
  "application/json": {
12501
12690
  /** @example success */
12502
12691
  status?: string;
12503
- data?: components["schemas"]["User"];
12692
+ data?: components["schemas"]["UsersCourseLogProgress"];
12504
12693
  };
12505
12694
  };
12506
12695
  };
12507
12696
  401: components["responses"]["Unauthorized"];
12508
- 500: components["responses"]["ServerError"];
12697
+ 404: components["responses"]["NotFound"];
12509
12698
  };
12510
12699
  };
12700
+ put?: never;
12701
+ post?: never;
12702
+ delete?: never;
12703
+ options?: never;
12704
+ head?: never;
12705
+ patch?: never;
12706
+ trace?: never;
12707
+ };
12708
+ "/users-course-log/me/courses/{courseId}/modules/{moduleId}/progress": {
12709
+ parameters: {
12710
+ query?: never;
12711
+ header?: never;
12712
+ path?: never;
12713
+ cookie?: never;
12714
+ };
12511
12715
  /**
12512
- * Update current authenticated user
12513
- * @description Updates the profile information of the currently authenticated user.
12514
- * Users can only update their own data (validated via JWT token).
12515
- *
12516
- * **Address Handling:**
12517
- * - If the user has no address, a new address will be created
12518
- * - If the user already has an address, it will be updated
12519
- * - Address fields are optional - only provided fields will be updated
12520
- *
12521
- * **Push Token Handling:**
12522
- * - If pushToken is provided, registers or updates the device push token
12523
- * - If the token already exists (same token string), updates it
12524
- * - If deviceId is provided and exists for this user, updates that device's token
12525
- * - Otherwise, creates a new push token record
12526
- * - Useful for registering FCM/APNs tokens on app startup or login
12716
+ * Get authenticated user's progress in a module
12717
+ * @description Returns completed/total active lessons of the module and a percentage based on
12718
+ * `users_course_log` completion events. Used by the Journey "curso" step.
12527
12719
  */
12528
- put: {
12720
+ get: {
12529
12721
  parameters: {
12530
12722
  query?: never;
12531
12723
  header?: never;
12532
- path?: never;
12724
+ path: {
12725
+ courseId: string;
12726
+ moduleId: string;
12727
+ };
12533
12728
  cookie?: never;
12534
12729
  };
12535
- requestBody: {
12536
- content: {
12537
- "application/json": {
12538
- /** @example sa@academe.com.br */
12539
- email?: string;
12540
- /** @example John */
12541
- firstName?: string;
12542
- /** @example Doe */
12543
- lastName?: string;
12544
- /** @example +5511999999999 */
12545
- phone?: string;
12546
- /** @example 12345678901 */
12547
- document?: string;
12548
- /**
12549
- * @example male
12550
- * @enum {string}
12551
- */
12552
- gender?: "male" | "female" | "other";
12553
- /**
12554
- * Format: date-time
12555
- * @example 1990-01-15T00:00:00.000Z
12556
- */
12557
- birthdate?: string;
12558
- /**
12730
+ requestBody?: never;
12731
+ responses: {
12732
+ /** @description Module progress snapshot */
12733
+ 200: {
12734
+ headers: {
12735
+ [name: string]: unknown;
12736
+ };
12737
+ content: {
12738
+ "application/json": {
12739
+ /** @example success */
12740
+ status?: string;
12741
+ data?: components["schemas"]["UsersCourseLogProgress"];
12742
+ };
12743
+ };
12744
+ };
12745
+ 401: components["responses"]["Unauthorized"];
12746
+ 404: components["responses"]["NotFound"];
12747
+ };
12748
+ };
12749
+ put?: never;
12750
+ post?: never;
12751
+ delete?: never;
12752
+ options?: never;
12753
+ head?: never;
12754
+ patch?: never;
12755
+ trace?: never;
12756
+ };
12757
+ "/users/me": {
12758
+ parameters: {
12759
+ query?: never;
12760
+ header?: never;
12761
+ path?: never;
12762
+ cookie?: never;
12763
+ };
12764
+ /**
12765
+ * Get current authenticated user
12766
+ * @description Returns the profile information of the currently authenticated user including:
12767
+ * - User groups (userGroups)
12768
+ * - User guardians (userGuardians)
12769
+ * - Certificates (certificates)
12770
+ * - Institution registrations with detailed classroom information (institutionRegistrations)
12771
+ * - Institution data
12772
+ * - Classroom assignment (institutionClassroom)
12773
+ * - Classroom details (name, shift, serie)
12774
+ * - Address information (address)
12775
+ */
12776
+ get: {
12777
+ parameters: {
12778
+ query?: never;
12779
+ header?: never;
12780
+ path?: never;
12781
+ cookie?: never;
12782
+ };
12783
+ requestBody?: never;
12784
+ responses: {
12785
+ /** @description Current user information with all related entities */
12786
+ 200: {
12787
+ headers: {
12788
+ [name: string]: unknown;
12789
+ };
12790
+ content: {
12791
+ "application/json": {
12792
+ /** @example success */
12793
+ status?: string;
12794
+ data?: components["schemas"]["User"];
12795
+ };
12796
+ };
12797
+ };
12798
+ 401: components["responses"]["Unauthorized"];
12799
+ 500: components["responses"]["ServerError"];
12800
+ };
12801
+ };
12802
+ /**
12803
+ * Update current authenticated user
12804
+ * @description Updates the profile information of the currently authenticated user.
12805
+ * Users can only update their own data (validated via JWT token).
12806
+ *
12807
+ * **Address Handling:**
12808
+ * - If the user has no address, a new address will be created
12809
+ * - If the user already has an address, it will be updated
12810
+ * - Address fields are optional - only provided fields will be updated
12811
+ *
12812
+ * **Push Token Handling:**
12813
+ * - If pushToken is provided, registers or updates the device push token
12814
+ * - If the token already exists (same token string), updates it
12815
+ * - If deviceId is provided and exists for this user, updates that device's token
12816
+ * - Otherwise, creates a new push token record
12817
+ * - Useful for registering FCM/APNs tokens on app startup or login
12818
+ */
12819
+ put: {
12820
+ parameters: {
12821
+ query?: never;
12822
+ header?: never;
12823
+ path?: never;
12824
+ cookie?: never;
12825
+ };
12826
+ requestBody: {
12827
+ content: {
12828
+ "application/json": {
12829
+ /** @example sa@academe.com.br */
12830
+ email?: string;
12831
+ /** @example John */
12832
+ firstName?: string;
12833
+ /** @example Doe */
12834
+ lastName?: string;
12835
+ /** @example +5511999999999 */
12836
+ phone?: string;
12837
+ /** @example 12345678901 */
12838
+ document?: string;
12839
+ /**
12840
+ * @example male
12841
+ * @enum {string}
12842
+ */
12843
+ gender?: "male" | "female" | "other";
12844
+ /**
12845
+ * Format: date-time
12846
+ * @example 1990-01-15T00:00:00.000Z
12847
+ */
12848
+ birthdate?: string;
12849
+ /**
12559
12850
  * Format: uuid
12560
12851
  * @example 550e8400-e29b-41d4-a716-446655440000
12561
12852
  */
@@ -12936,7 +13227,19 @@ interface paths {
12936
13227
  head?: never;
12937
13228
  /**
12938
13229
  * Update user
12939
- * @description Update user information
13230
+ * @description Update user information.
13231
+ *
13232
+ * **Profile and seat code behavior:**
13233
+ * - Send `groupId` to change the user's profile/group.
13234
+ * - When `groupId` changes, the system will:
13235
+ * 1. Release the previous seat code used by the user (`isReserved = false`)
13236
+ * 2. Allocate a seat code for the new group in the same institution registration
13237
+ * 3. Create a new seat code automatically if none is available for that group
13238
+ *
13239
+ * **Important:**
13240
+ * - The target group must exist.
13241
+ * - The institution must have a seat configured for the target group.
13242
+ * - If any institution registration cannot be migrated to the new group, the operation fails.
12940
13243
  */
12941
13244
  patch: {
12942
13245
  parameters: {
@@ -14754,6 +15057,29 @@ interface components {
14754
15057
  /** Format: date-time */
14755
15058
  updatedAt?: string;
14756
15059
  };
15060
+ /** @description Aggregated progress of a user on a course or module, derived from users_course_log completion events */
15061
+ UsersCourseLogProgress: {
15062
+ /**
15063
+ * @description Number of active lessons completed by the user
15064
+ * @example 3
15065
+ */
15066
+ completedLessons?: number;
15067
+ /**
15068
+ * @description Total number of active lessons in scope
15069
+ * @example 5
15070
+ */
15071
+ totalLessons?: number;
15072
+ /**
15073
+ * @description Completion percentage rounded to nearest integer
15074
+ * @example 60
15075
+ */
15076
+ percent?: number;
15077
+ /**
15078
+ * @description True when totalLessons > 0 and completedLessons >= totalLessons
15079
+ * @example false
15080
+ */
15081
+ isCompleted?: boolean;
15082
+ };
14757
15083
  Submission: {
14758
15084
  /** Format: uuid */
14759
15085
  id?: string;
@@ -15861,6 +16187,27 @@ interface components {
15861
16187
  /** Format: uri */
15862
16188
  url?: string;
15863
16189
  };
16190
+ GenerateCertificateDto: {
16191
+ /** Format: uuid */
16192
+ userId: string;
16193
+ /** Format: uuid */
16194
+ quizAttemptId?: string;
16195
+ /** Format: uuid */
16196
+ certificateTemplateId: string;
16197
+ /** @example João Silva */
16198
+ studentName: string;
16199
+ /** @example Introdução ao JavaScript */
16200
+ quizTitle: string;
16201
+ /** @example 85 */
16202
+ score?: number;
16203
+ /** @example CERT-2024-000001 */
16204
+ certificateNumber?: string;
16205
+ /**
16206
+ * Format: date-time
16207
+ * @example 2024-01-01T00:00:00.000Z
16208
+ */
16209
+ issuedAt?: string;
16210
+ };
15864
16211
  CreateGuardianDto: {
15865
16212
  /**
15866
16213
  * Format: email
@@ -22244,7 +22591,6 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
22244
22591
  "application/json": {
22245
22592
  status?: string;
22246
22593
  data?: components["schemas"]["Certificate"];
22247
- message?: string;
22248
22594
  };
22249
22595
  };
22250
22596
  };
@@ -22291,7 +22637,6 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
22291
22637
  "application/json": {
22292
22638
  status?: string;
22293
22639
  data?: components["schemas"]["Certificate"];
22294
- message?: string;
22295
22640
  };
22296
22641
  };
22297
22642
  };
@@ -22327,16 +22672,11 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
22327
22672
  };
22328
22673
  requestBody?: never;
22329
22674
  responses: {
22330
- 200: {
22675
+ 204: {
22331
22676
  headers: {
22332
22677
  [name: string]: unknown;
22333
22678
  };
22334
- content: {
22335
- "application/json": {
22336
- status?: string;
22337
- message?: string;
22338
- };
22339
- };
22679
+ content?: never;
22340
22680
  };
22341
22681
  400: components["responses"]["BadRequest"];
22342
22682
  401: components["responses"]["Unauthorized"];
@@ -25110,6 +25450,353 @@ declare function createStepService(apiClient: AcademeApiClient): {
25110
25450
  };
25111
25451
  type StepService = ReturnType<typeof createStepService>;
25112
25452
 
25453
+ type GetSubmissionsParams = paths["/submissions"]["get"]["parameters"]["query"];
25454
+ type CreateSubmissionBody = paths["/submissions"]["post"]["requestBody"]["content"]["application/json"] & {
25455
+ /** Institution under which the user is submitting (from institution_registration) */
25456
+ institutionId: string;
25457
+ };
25458
+ type AttachFilesBody = paths["/submissions/{id}/files"]["post"]["requestBody"]["content"]["application/json"];
25459
+ type AiEvaluationBody = paths["/submissions/{id}/ai-evaluation"]["post"]["requestBody"]["content"]["application/json"];
25460
+ type TeacherEvaluationBody = paths["/submissions/{id}/teacher-evaluation"]["patch"]["requestBody"]["content"]["application/json"];
25461
+ declare function createSubmissionService(apiClient: AcademeApiClient): {
25462
+ /**
25463
+ * List submissions with filters and pagination
25464
+ */
25465
+ getAll(params?: GetSubmissionsParams): Promise<openapi_fetch.FetchResponse<{
25466
+ parameters: {
25467
+ query?: {
25468
+ challengeId?: string;
25469
+ userId?: string;
25470
+ groupId?: string;
25471
+ institutionId?: string;
25472
+ status?: "submitted" | "ai_evaluated" | "approved" | "rejected";
25473
+ page?: components["parameters"]["page"];
25474
+ limit?: components["parameters"]["limit"];
25475
+ };
25476
+ header?: never;
25477
+ path?: never;
25478
+ cookie?: never;
25479
+ };
25480
+ requestBody?: never;
25481
+ responses: {
25482
+ 200: {
25483
+ headers: {
25484
+ [name: string]: unknown;
25485
+ };
25486
+ content: {
25487
+ "application/json": {
25488
+ status?: string;
25489
+ data?: components["schemas"]["Submission"][];
25490
+ meta?: components["schemas"]["PaginationMeta"];
25491
+ };
25492
+ };
25493
+ };
25494
+ 401: components["responses"]["Unauthorized"];
25495
+ };
25496
+ }, {
25497
+ params: {
25498
+ query: {
25499
+ challengeId?: string;
25500
+ userId?: string;
25501
+ groupId?: string;
25502
+ institutionId?: string;
25503
+ status?: "submitted" | "ai_evaluated" | "approved" | "rejected";
25504
+ page?: components["parameters"]["page"];
25505
+ limit?: components["parameters"]["limit"];
25506
+ } | undefined;
25507
+ };
25508
+ }, `${string}/${string}`>>;
25509
+ /**
25510
+ * Get submission with files and per-criterion scores
25511
+ */
25512
+ getById(id: string): Promise<openapi_fetch.FetchResponse<{
25513
+ parameters: {
25514
+ query?: never;
25515
+ header?: never;
25516
+ path: {
25517
+ id: components["parameters"]["id"];
25518
+ };
25519
+ cookie?: never;
25520
+ };
25521
+ requestBody?: never;
25522
+ responses: {
25523
+ 200: {
25524
+ headers: {
25525
+ [name: string]: unknown;
25526
+ };
25527
+ content: {
25528
+ "application/json": {
25529
+ status?: string;
25530
+ data?: components["schemas"]["Submission"] & {
25531
+ files?: components["schemas"]["SubmissionFile"][];
25532
+ criterionScores?: components["schemas"]["SubmissionCriterionScore"][];
25533
+ };
25534
+ };
25535
+ };
25536
+ };
25537
+ 401: components["responses"]["Unauthorized"];
25538
+ 404: components["responses"]["NotFound"];
25539
+ };
25540
+ }, {
25541
+ params: {
25542
+ path: {
25543
+ id: string;
25544
+ };
25545
+ };
25546
+ }, `${string}/${string}`>>;
25547
+ /**
25548
+ * Create a new submission attempt (status=submitted)
25549
+ * - Cannot submit to a global template (clone first)
25550
+ * - For group challenges: groupId is required and user must be a member
25551
+ * - For individual challenges: groupId must be omitted
25552
+ * - Cannot create when there is already an active submission
25553
+ * - attempt_number is computed server-side
25554
+ */
25555
+ create(data: CreateSubmissionBody): Promise<openapi_fetch.FetchResponse<{
25556
+ parameters: {
25557
+ query?: never;
25558
+ header?: never;
25559
+ path?: never;
25560
+ cookie?: never;
25561
+ };
25562
+ requestBody: {
25563
+ content: {
25564
+ "application/json": {
25565
+ challengeId: string;
25566
+ institutionId: string;
25567
+ groupId?: string;
25568
+ description?: string;
25569
+ };
25570
+ };
25571
+ };
25572
+ responses: {
25573
+ 201: {
25574
+ headers: {
25575
+ [name: string]: unknown;
25576
+ };
25577
+ content: {
25578
+ "application/json": {
25579
+ status?: string;
25580
+ data?: components["schemas"]["Submission"];
25581
+ };
25582
+ };
25583
+ };
25584
+ 400: components["responses"]["BadRequest"];
25585
+ 403: components["responses"]["Forbidden"];
25586
+ 404: components["responses"]["NotFound"];
25587
+ 409: components["responses"]["Conflict"];
25588
+ };
25589
+ }, {
25590
+ body: never;
25591
+ }, `${string}/${string}`>>;
25592
+ /**
25593
+ * Attach files or links to a submission (batch)
25594
+ * Each item must have exactly ONE of fileId or url (XOR).
25595
+ * - submissionType in [images, videos, audio, files] → items must have fileId
25596
+ * - submissionType === 'links' → items must have url
25597
+ */
25598
+ attachFiles(submissionId: string, data: AttachFilesBody): Promise<openapi_fetch.FetchResponse<{
25599
+ parameters: {
25600
+ query?: never;
25601
+ header?: never;
25602
+ path: {
25603
+ id: components["parameters"]["id"];
25604
+ };
25605
+ cookie?: never;
25606
+ };
25607
+ requestBody: {
25608
+ content: {
25609
+ "application/json": {
25610
+ items: {
25611
+ fileId?: string | null;
25612
+ url?: string | null;
25613
+ index?: number;
25614
+ }[];
25615
+ };
25616
+ };
25617
+ };
25618
+ responses: {
25619
+ 201: {
25620
+ headers: {
25621
+ [name: string]: unknown;
25622
+ };
25623
+ content: {
25624
+ "application/json": {
25625
+ status?: string;
25626
+ data?: components["schemas"]["SubmissionFile"][];
25627
+ };
25628
+ };
25629
+ };
25630
+ 400: components["responses"]["BadRequest"];
25631
+ 404: components["responses"]["NotFound"];
25632
+ 409: components["responses"]["Conflict"];
25633
+ };
25634
+ }, {
25635
+ params: {
25636
+ path: {
25637
+ id: string;
25638
+ };
25639
+ };
25640
+ body: {
25641
+ items: {
25642
+ fileId?: string | null;
25643
+ url?: string | null;
25644
+ index?: number;
25645
+ }[];
25646
+ };
25647
+ }, `${string}/${string}`>>;
25648
+ /**
25649
+ * Remove a file or link from a submission
25650
+ * Only allowed when submission is in status submitted or ai_evaluated
25651
+ */
25652
+ removeFile(submissionId: string, fileRowId: string): Promise<openapi_fetch.FetchResponse<{
25653
+ parameters: {
25654
+ query?: never;
25655
+ header?: never;
25656
+ path: {
25657
+ id: components["parameters"]["id"];
25658
+ fileRowId: string;
25659
+ };
25660
+ cookie?: never;
25661
+ };
25662
+ requestBody?: never;
25663
+ responses: {
25664
+ 204: {
25665
+ headers: {
25666
+ [name: string]: unknown;
25667
+ };
25668
+ content?: never;
25669
+ };
25670
+ 400: components["responses"]["BadRequest"];
25671
+ 404: components["responses"]["NotFound"];
25672
+ };
25673
+ }, {
25674
+ params: {
25675
+ path: {
25676
+ id: string;
25677
+ fileRowId: string;
25678
+ };
25679
+ };
25680
+ }, `${string}/${string}`>>;
25681
+ /**
25682
+ * Register AI evaluation (called by the AI service callback).
25683
+ * Moves status from submitted → ai_evaluated.
25684
+ */
25685
+ aiEvaluate(submissionId: string, data: AiEvaluationBody): Promise<openapi_fetch.FetchResponse<{
25686
+ parameters: {
25687
+ query?: never;
25688
+ header?: never;
25689
+ path: {
25690
+ id: components["parameters"]["id"];
25691
+ };
25692
+ cookie?: never;
25693
+ };
25694
+ requestBody: {
25695
+ content: {
25696
+ "application/json": {
25697
+ aiScore: number;
25698
+ aiFeedback?: string;
25699
+ aiExtractedContent?: Record<string, never>;
25700
+ criterionScores?: {
25701
+ challengeEvaluationCriterionId: string;
25702
+ score: number;
25703
+ comment?: string;
25704
+ }[];
25705
+ };
25706
+ };
25707
+ };
25708
+ responses: {
25709
+ 200: {
25710
+ headers: {
25711
+ [name: string]: unknown;
25712
+ };
25713
+ content: {
25714
+ "application/json": {
25715
+ status?: string;
25716
+ data?: components["schemas"]["Submission"];
25717
+ };
25718
+ };
25719
+ };
25720
+ 400: {
25721
+ headers: {
25722
+ [name: string]: unknown;
25723
+ };
25724
+ content: {
25725
+ "application/json": components["schemas"]["Error"];
25726
+ };
25727
+ };
25728
+ 404: components["responses"]["NotFound"];
25729
+ 409: components["responses"]["Conflict"];
25730
+ };
25731
+ }, {
25732
+ params: {
25733
+ path: {
25734
+ id: string;
25735
+ };
25736
+ };
25737
+ body: {
25738
+ aiScore: number;
25739
+ aiFeedback?: string;
25740
+ aiExtractedContent?: Record<string, never>;
25741
+ criterionScores?: {
25742
+ challengeEvaluationCriterionId: string;
25743
+ score: number;
25744
+ comment?: string;
25745
+ }[];
25746
+ };
25747
+ }, `${string}/${string}`>>;
25748
+ /**
25749
+ * Teacher approves or rejects a submission.
25750
+ * Only allowed when status is submitted or ai_evaluated.
25751
+ */
25752
+ teacherEvaluate(submissionId: string, data: TeacherEvaluationBody): Promise<openapi_fetch.FetchResponse<{
25753
+ parameters: {
25754
+ query?: never;
25755
+ header?: never;
25756
+ path: {
25757
+ id: components["parameters"]["id"];
25758
+ };
25759
+ cookie?: never;
25760
+ };
25761
+ requestBody: {
25762
+ content: {
25763
+ "application/json": {
25764
+ status: "approved" | "rejected";
25765
+ teacherScore?: number;
25766
+ teacherFeedback?: string;
25767
+ };
25768
+ };
25769
+ };
25770
+ responses: {
25771
+ 200: {
25772
+ headers: {
25773
+ [name: string]: unknown;
25774
+ };
25775
+ content: {
25776
+ "application/json": {
25777
+ status?: string;
25778
+ data?: components["schemas"]["Submission"];
25779
+ };
25780
+ };
25781
+ };
25782
+ 400: components["responses"]["BadRequest"];
25783
+ 404: components["responses"]["NotFound"];
25784
+ };
25785
+ }, {
25786
+ params: {
25787
+ path: {
25788
+ id: string;
25789
+ };
25790
+ };
25791
+ body: {
25792
+ status: "approved" | "rejected";
25793
+ teacherScore?: number;
25794
+ teacherFeedback?: string;
25795
+ };
25796
+ }, `${string}/${string}`>>;
25797
+ };
25798
+ type SubmissionService = ReturnType<typeof createSubmissionService>;
25799
+
25113
25800
  type AcademeApiClient = ReturnType<typeof openapi_fetch__default<paths>>;
25114
25801
  declare function createAcademeApiClient(baseUrl: string): AcademeApiClient;
25115
25802
  interface AcademeServices {
@@ -25133,6 +25820,7 @@ interface AcademeServices {
25133
25820
  storageFile: StorageFileService;
25134
25821
  challenge: ChallengeService;
25135
25822
  step: StepService;
25823
+ submission: SubmissionService;
25136
25824
  }
25137
25825
 
25138
25826
  type AcademeKeycloakContextProps = {