academe-kit 0.9.0 → 0.9.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/dist/index.d.ts CHANGED
@@ -270,6 +270,221 @@ interface paths {
270
270
  };
271
271
  trace?: never;
272
272
  };
273
+ "/auth/forgot-password": {
274
+ parameters: {
275
+ query?: never;
276
+ header?: never;
277
+ path?: never;
278
+ cookie?: never;
279
+ };
280
+ get?: never;
281
+ put?: never;
282
+ /**
283
+ * Request password reset email
284
+ * @description Sends a password reset email to the specified address if a user with that email exists.
285
+ *
286
+ * **Security Note:**
287
+ * For security reasons, this endpoint always returns a success response regardless of whether
288
+ * the email exists in the system. This prevents email enumeration attacks.
289
+ *
290
+ * **Flow:**
291
+ * 1. Client sends email address
292
+ * 2. Backend searches for user by email in Keycloak
293
+ * 3. If user exists, Keycloak sends password reset email with UPDATE_PASSWORD action
294
+ * 4. User receives email with link valid for 1 hour
295
+ * 5. Endpoint returns success (regardless of whether email was found)
296
+ *
297
+ * **Email Template:**
298
+ * The email sent uses the Keycloak realm's configured email template for password reset.
299
+ */
300
+ post: {
301
+ parameters: {
302
+ query?: never;
303
+ header?: never;
304
+ path?: never;
305
+ cookie?: never;
306
+ };
307
+ requestBody: {
308
+ content: {
309
+ "application/json": {
310
+ /**
311
+ * Format: email
312
+ * @description User's email address
313
+ * @example user@example.com
314
+ */
315
+ email: string;
316
+ };
317
+ };
318
+ };
319
+ responses: {
320
+ /** @description Request processed successfully (always returned for security) */
321
+ 200: {
322
+ headers: {
323
+ [name: string]: unknown;
324
+ };
325
+ content: {
326
+ "application/json": {
327
+ /** @example success */
328
+ status?: string;
329
+ /** @example If this email is registered, you will receive password reset instructions. */
330
+ message?: string;
331
+ };
332
+ };
333
+ };
334
+ /** @description Bad Request - Email not provided */
335
+ 400: {
336
+ headers: {
337
+ [name: string]: unknown;
338
+ };
339
+ content: {
340
+ "application/json": {
341
+ /** @example error */
342
+ status?: string;
343
+ /** @example Email is required */
344
+ message?: string;
345
+ };
346
+ };
347
+ };
348
+ /** @description Internal Server Error */
349
+ 500: {
350
+ headers: {
351
+ [name: string]: unknown;
352
+ };
353
+ content: {
354
+ "application/json": {
355
+ /** @example error */
356
+ status?: string;
357
+ /** @example Internal server error */
358
+ message?: string;
359
+ };
360
+ };
361
+ };
362
+ };
363
+ };
364
+ delete?: never;
365
+ options?: never;
366
+ head?: never;
367
+ patch?: never;
368
+ trace?: never;
369
+ };
370
+ "/auth/google-exchange": {
371
+ parameters: {
372
+ query?: never;
373
+ header?: never;
374
+ path?: never;
375
+ cookie?: never;
376
+ };
377
+ get?: never;
378
+ put?: never;
379
+ /**
380
+ * Exchange Google access token for Keycloak tokens
381
+ * @description Exchanges a Google access token for Keycloak tokens.
382
+ *
383
+ * **Flow:**
384
+ * 1. Client sends Google access token
385
+ * 2. Backend fetches user email from Google Userinfo API
386
+ * 3. Backend verifies the email exists in the local database
387
+ * 4. If user exists, performs Keycloak token exchange
388
+ * 5. Returns Keycloak tokens (access_token, refresh_token, etc.)
389
+ *
390
+ * **Error Cases:**
391
+ * - 400: Invalid or expired Google token
392
+ * - 404: User email not found in database
393
+ */
394
+ post: {
395
+ parameters: {
396
+ query?: never;
397
+ header?: never;
398
+ path?: never;
399
+ cookie?: never;
400
+ };
401
+ requestBody: {
402
+ content: {
403
+ "application/json": {
404
+ /**
405
+ * @description Google OAuth2 access token
406
+ * @example ya29.a0AfH6SM...
407
+ */
408
+ googleAccessToken: string;
409
+ };
410
+ };
411
+ };
412
+ responses: {
413
+ /** @description Token exchange successful */
414
+ 200: {
415
+ headers: {
416
+ [name: string]: unknown;
417
+ };
418
+ content: {
419
+ "application/json": {
420
+ /** @example success */
421
+ status?: string;
422
+ data?: {
423
+ /** @description Keycloak access token */
424
+ access_token?: string;
425
+ /** @description Keycloak refresh token */
426
+ refresh_token?: string;
427
+ /** @description Token expiration time in seconds */
428
+ expires_in?: number;
429
+ /** @description Refresh token expiration time in seconds */
430
+ refresh_expires_in?: number;
431
+ /** @example Bearer */
432
+ token_type?: string;
433
+ scope?: string;
434
+ };
435
+ };
436
+ };
437
+ };
438
+ /** @description Bad Request - Invalid Google token or missing googleAccessToken */
439
+ 400: {
440
+ headers: {
441
+ [name: string]: unknown;
442
+ };
443
+ content: {
444
+ "application/json": {
445
+ /** @example error */
446
+ status?: string;
447
+ /** @example Token do Google inválido ou expirado */
448
+ message?: string;
449
+ };
450
+ };
451
+ };
452
+ /** @description Not Found - User email not registered in database */
453
+ 404: {
454
+ headers: {
455
+ [name: string]: unknown;
456
+ };
457
+ content: {
458
+ "application/json": {
459
+ /** @example error */
460
+ status?: string;
461
+ /** @example Usuário não encontrado */
462
+ message?: string;
463
+ };
464
+ };
465
+ };
466
+ /** @description Internal Server Error */
467
+ 500: {
468
+ headers: {
469
+ [name: string]: unknown;
470
+ };
471
+ content: {
472
+ "application/json": {
473
+ /** @example error */
474
+ status?: string;
475
+ /** @example Internal server error */
476
+ message?: string;
477
+ };
478
+ };
479
+ };
480
+ };
481
+ };
482
+ delete?: never;
483
+ options?: never;
484
+ head?: never;
485
+ patch?: never;
486
+ trace?: never;
487
+ };
273
488
  "/auth/token": {
274
489
  parameters: {
275
490
  query?: never;
@@ -872,6 +1087,68 @@ interface paths {
872
1087
  patch?: never;
873
1088
  trace?: never;
874
1089
  };
1090
+ "/certificates/{userId}/download-all": {
1091
+ parameters: {
1092
+ query?: never;
1093
+ header?: never;
1094
+ path?: never;
1095
+ cookie?: never;
1096
+ };
1097
+ /**
1098
+ * Download all certificates of a user as a single PDF
1099
+ * @description Downloads all certificates of the given user merged into a single PDF file.
1100
+ * Each certificate occupies one page in the resulting file.
1101
+ * PDFs are downloaded from S3 in parallel and merged using pdf-lib.
1102
+ */
1103
+ get: {
1104
+ parameters: {
1105
+ query?: never;
1106
+ header?: never;
1107
+ path: {
1108
+ /** @description ID of the user whose certificates will be downloaded */
1109
+ userId: string;
1110
+ };
1111
+ cookie?: never;
1112
+ };
1113
+ requestBody?: never;
1114
+ responses: {
1115
+ /** @description Merged PDF file containing all user certificates */
1116
+ 200: {
1117
+ headers: {
1118
+ /** @description attachment; filename="Meus-Certificados.pdf" */
1119
+ "Content-Disposition"?: string;
1120
+ [name: string]: unknown;
1121
+ };
1122
+ content: {
1123
+ "application/pdf": string;
1124
+ };
1125
+ };
1126
+ 401: components["responses"]["Unauthorized"];
1127
+ /** @description No certificates found for the user */
1128
+ 404: {
1129
+ headers: {
1130
+ [name: string]: unknown;
1131
+ };
1132
+ content: {
1133
+ "application/json": {
1134
+ /** @example error */
1135
+ status?: string;
1136
+ /** @example No certificates found for this user */
1137
+ message?: string;
1138
+ };
1139
+ };
1140
+ };
1141
+ 500: components["responses"]["ServerError"];
1142
+ };
1143
+ };
1144
+ put?: never;
1145
+ post?: never;
1146
+ delete?: never;
1147
+ options?: never;
1148
+ head?: never;
1149
+ patch?: never;
1150
+ trace?: never;
1151
+ };
875
1152
  "/certificates": {
876
1153
  parameters: {
877
1154
  query?: never;
@@ -881,13 +1158,24 @@ interface paths {
881
1158
  };
882
1159
  /**
883
1160
  * List all certificates
884
- * @description Retrieve a list of all certificates in the system.
1161
+ * @description Retrieve a paginated list of all certificates in the system.
885
1162
  * Each certificate includes course information (id, title, description) when available.
886
1163
  * Course data is extracted from the related Quiz through QuizAttempt.
887
1164
  */
888
1165
  get: {
889
1166
  parameters: {
890
- query?: never;
1167
+ query?: {
1168
+ /** @description Filter certificates by user ID */
1169
+ userId?: string;
1170
+ /** @description Search term */
1171
+ search?: components["parameters"]["search"];
1172
+ /** @description Page number */
1173
+ page?: components["parameters"]["page"];
1174
+ /** @description Items per page */
1175
+ limit?: components["parameters"]["limit"];
1176
+ /** @description Whether to include course data in the response (default true). Pass false to skip course lookup. */
1177
+ includeCourse?: boolean;
1178
+ };
891
1179
  header?: never;
892
1180
  path?: never;
893
1181
  cookie?: never;
@@ -904,6 +1192,16 @@ interface paths {
904
1192
  /** @example success */
905
1193
  status?: string;
906
1194
  data?: components["schemas"]["Certificate"][];
1195
+ meta?: {
1196
+ /** @example 10 */
1197
+ total?: number;
1198
+ /** @example 1 */
1199
+ page?: number;
1200
+ /** @example 10 */
1201
+ limit?: number;
1202
+ /** @example 1 */
1203
+ totalPages?: number;
1204
+ };
907
1205
  };
908
1206
  };
909
1207
  };
@@ -939,8 +1237,6 @@ interface paths {
939
1237
  /** @example success */
940
1238
  status?: string;
941
1239
  data?: components["schemas"]["Certificate"];
942
- /** @example Certificate created successfully */
943
- message?: string;
944
1240
  };
945
1241
  };
946
1242
  };
@@ -1018,18 +1314,11 @@ interface paths {
1018
1314
  requestBody?: never;
1019
1315
  responses: {
1020
1316
  /** @description Certificate deleted successfully */
1021
- 200: {
1317
+ 204: {
1022
1318
  headers: {
1023
1319
  [name: string]: unknown;
1024
1320
  };
1025
- content: {
1026
- "application/json": {
1027
- /** @example success */
1028
- status?: string;
1029
- /** @example Certificate deleted successfully */
1030
- message?: string;
1031
- };
1032
- };
1321
+ content?: never;
1033
1322
  };
1034
1323
  400: components["responses"]["BadRequest"];
1035
1324
  401: components["responses"]["Unauthorized"];
@@ -1069,8 +1358,6 @@ interface paths {
1069
1358
  /** @example success */
1070
1359
  status?: string;
1071
1360
  data?: components["schemas"]["Certificate"];
1072
- /** @example Certificate updated successfully */
1073
- message?: string;
1074
1361
  };
1075
1362
  };
1076
1363
  };
@@ -1082,6 +1369,109 @@ interface paths {
1082
1369
  };
1083
1370
  trace?: never;
1084
1371
  };
1372
+ "/certificates/{id}/download": {
1373
+ parameters: {
1374
+ query?: never;
1375
+ header?: never;
1376
+ path?: never;
1377
+ cookie?: never;
1378
+ };
1379
+ /**
1380
+ * Download certificate PDF
1381
+ * @description Download the PDF of a specific certificate.
1382
+ * Acts as a proxy to download from S3, avoiding CORS issues.
1383
+ * Only the certificate owner can download their certificate.
1384
+ */
1385
+ get: {
1386
+ parameters: {
1387
+ query?: never;
1388
+ header?: never;
1389
+ path: {
1390
+ /** @description Resource ID */
1391
+ id: components["parameters"]["id"];
1392
+ };
1393
+ cookie?: never;
1394
+ };
1395
+ requestBody?: never;
1396
+ responses: {
1397
+ /** @description Certificate PDF file */
1398
+ 200: {
1399
+ headers: {
1400
+ [name: string]: unknown;
1401
+ };
1402
+ content: {
1403
+ "application/pdf": string;
1404
+ };
1405
+ };
1406
+ 401: components["responses"]["Unauthorized"];
1407
+ 403: components["responses"]["Forbidden"];
1408
+ 404: components["responses"]["NotFound"];
1409
+ 500: components["responses"]["ServerError"];
1410
+ };
1411
+ };
1412
+ put?: never;
1413
+ post?: never;
1414
+ delete?: never;
1415
+ options?: never;
1416
+ head?: never;
1417
+ patch?: never;
1418
+ trace?: never;
1419
+ };
1420
+ "/certificates/generate": {
1421
+ parameters: {
1422
+ query?: never;
1423
+ header?: never;
1424
+ path?: never;
1425
+ cookie?: never;
1426
+ };
1427
+ get?: never;
1428
+ put?: never;
1429
+ /**
1430
+ * Generate a certificate PDF server-side
1431
+ * @description Generates a certificate PDF on the server and creates the certificate record.
1432
+ * This eliminates CORS issues by downloading the template image on the server.
1433
+ */
1434
+ post: {
1435
+ parameters: {
1436
+ query?: never;
1437
+ header?: never;
1438
+ path?: never;
1439
+ cookie?: never;
1440
+ };
1441
+ requestBody: {
1442
+ content: {
1443
+ "application/json": components["schemas"]["GenerateCertificateDto"];
1444
+ };
1445
+ };
1446
+ responses: {
1447
+ /** @description Certificate generated and created successfully */
1448
+ 201: {
1449
+ headers: {
1450
+ [name: string]: unknown;
1451
+ };
1452
+ content: {
1453
+ "application/json": {
1454
+ /** @example success */
1455
+ status?: string;
1456
+ data?: {
1457
+ certificate?: components["schemas"]["Certificate"];
1458
+ /** @example https://s3.amazonaws.com/bucket/certificate.pdf */
1459
+ pdfUrl?: string;
1460
+ };
1461
+ };
1462
+ };
1463
+ };
1464
+ 400: components["responses"]["BadRequest"];
1465
+ 401: components["responses"]["Unauthorized"];
1466
+ 500: components["responses"]["ServerError"];
1467
+ };
1468
+ };
1469
+ delete?: never;
1470
+ options?: never;
1471
+ head?: never;
1472
+ patch?: never;
1473
+ trace?: never;
1474
+ };
1085
1475
  "/classrooms": {
1086
1476
  parameters: {
1087
1477
  query?: never;
@@ -9589,6 +9979,8 @@ interface paths {
9589
9979
  requestBody: {
9590
9980
  content: {
9591
9981
  "application/json": {
9982
+ /** @example sa@academe.com.br */
9983
+ email?: string;
9592
9984
  /** @example John */
9593
9985
  firstName?: string;
9594
9986
  /** @example Doe */
@@ -9988,7 +10380,19 @@ interface paths {
9988
10380
  head?: never;
9989
10381
  /**
9990
10382
  * Update user
9991
- * @description Update user information
10383
+ * @description Update user information.
10384
+ *
10385
+ * **Profile and seat code behavior:**
10386
+ * - Send `groupId` to change the user's profile/group.
10387
+ * - When `groupId` changes, the system will:
10388
+ * 1. Release the previous seat code used by the user (`isReserved = false`)
10389
+ * 2. Allocate a seat code for the new group in the same institution registration
10390
+ * 3. Create a new seat code automatically if none is available for that group
10391
+ *
10392
+ * **Important:**
10393
+ * - The target group must exist.
10394
+ * - The institution must have a seat configured for the target group.
10395
+ * - If any institution registration cannot be migrated to the new group, the operation fails.
9992
10396
  */
9993
10397
  patch: {
9994
10398
  parameters: {
@@ -10252,7 +10656,59 @@ interface paths {
10252
10656
  patch?: never;
10253
10657
  trace?: never;
10254
10658
  };
10255
- "/users/{id}/sync": {
10659
+ "/users/{id}/sync": {
10660
+ parameters: {
10661
+ query?: never;
10662
+ header?: never;
10663
+ path?: never;
10664
+ cookie?: never;
10665
+ };
10666
+ get?: never;
10667
+ put?: never;
10668
+ /**
10669
+ * Sync user with Keycloak
10670
+ * @description Synchronize user data with Keycloak identity provider
10671
+ */
10672
+ post: {
10673
+ parameters: {
10674
+ query?: never;
10675
+ header?: never;
10676
+ path: {
10677
+ /** @description Resource ID */
10678
+ id: components["parameters"]["id"];
10679
+ };
10680
+ cookie?: never;
10681
+ };
10682
+ requestBody?: never;
10683
+ responses: {
10684
+ /** @description User synchronized successfully */
10685
+ 200: {
10686
+ headers: {
10687
+ [name: string]: unknown;
10688
+ };
10689
+ content: {
10690
+ "application/json": {
10691
+ /** @example success */
10692
+ status?: string;
10693
+ data?: components["schemas"]["User"];
10694
+ /** @example User synchronized with Keycloak successfully */
10695
+ message?: string;
10696
+ };
10697
+ };
10698
+ };
10699
+ 400: components["responses"]["BadRequest"];
10700
+ 401: components["responses"]["Unauthorized"];
10701
+ 404: components["responses"]["NotFound"];
10702
+ 500: components["responses"]["ServerError"];
10703
+ };
10704
+ };
10705
+ delete?: never;
10706
+ options?: never;
10707
+ head?: never;
10708
+ patch?: never;
10709
+ trace?: never;
10710
+ };
10711
+ "/users/register-hotmart": {
10256
10712
  parameters: {
10257
10713
  query?: never;
10258
10714
  header?: never;
@@ -10262,22 +10718,123 @@ interface paths {
10262
10718
  get?: never;
10263
10719
  put?: never;
10264
10720
  /**
10265
- * Sync user with Keycloak
10266
- * @description Synchronize user data with Keycloak identity provider
10721
+ * Hotmart webhook for user registration and lifecycle
10722
+ * @description Public endpoint that receives webhook events from Hotmart.
10723
+ * Handles user creation and deactivation based on purchase events.
10724
+ *
10725
+ * **Supported Events:**
10726
+ *
10727
+ * | Event | Action |
10728
+ * |-------|--------|
10729
+ * | `PURCHASE_APPROVED` | Enqueues user creation with buyer data |
10730
+ * | `PURCHASE_CANCELED` | Deactivates (soft deletes) the user |
10731
+ * | `PURCHASE_REFUNDED` | Deactivates (soft deletes) the user |
10732
+ * | `PURCHASE_CHARGEBACK` | Deactivates (soft deletes) the user |
10733
+ *
10734
+ * **User Creation Flow (PURCHASE_APPROVED):**
10735
+ * 1. Extracts buyer information from the Hotmart payload
10736
+ * 2. Determines institution based on offer code
10737
+ * 3. Enqueues user creation request for async processing
10738
+ * 4. User is created in Keycloak and database by the worker
10739
+ *
10740
+ * **Offer-based Institution Assignment:**
10741
+ * - Offer code `d9to7y3w` → Institution `580268b1-458d-4f4c-901d-281eccf3b40d`
10742
+ *
10743
+ * **User Deactivation Flow:**
10744
+ * 1. Looks up the user by buyer email
10745
+ * 2. Soft deletes the user (marks as inactive)
10746
+ * 3. Disables the user in Keycloak
10747
+ *
10748
+ * All events return HTTP 200 to acknowledge receipt.
10749
+ * Unrecognized events are logged and ignored.
10267
10750
  */
10268
10751
  post: {
10269
10752
  parameters: {
10270
10753
  query?: never;
10271
10754
  header?: never;
10272
- path: {
10273
- /** @description Resource ID */
10274
- id: components["parameters"]["id"];
10275
- };
10755
+ path?: never;
10276
10756
  cookie?: never;
10277
10757
  };
10278
- requestBody?: never;
10758
+ requestBody: {
10759
+ content: {
10760
+ "application/json": {
10761
+ /**
10762
+ * Format: uuid
10763
+ * @description Unique webhook event ID
10764
+ * @example d96fafd0-75ed-4ca7-8fa8-c6a57f48e384
10765
+ */
10766
+ id: string;
10767
+ /**
10768
+ * @description Hotmart event type
10769
+ * @example PURCHASE_APPROVED
10770
+ * @enum {string}
10771
+ */
10772
+ event: "PURCHASE_APPROVED" | "PURCHASE_CANCELED" | "PURCHASE_REFUNDED" | "PURCHASE_CHARGEBACK" | "PURCHASE_COMPLETE" | "PURCHASE_PROTEST" | "PURCHASE_DELAYED";
10773
+ /**
10774
+ * @description Event creation timestamp (Unix milliseconds)
10775
+ * @example 1773161133350
10776
+ */
10777
+ creation_date: number;
10778
+ /**
10779
+ * @description Webhook payload version
10780
+ * @example 2.0.0
10781
+ */
10782
+ version: string;
10783
+ data: {
10784
+ buyer: {
10785
+ /**
10786
+ * Format: email
10787
+ * @example buyer@example.com
10788
+ */
10789
+ email: string;
10790
+ /** @example Teste */
10791
+ first_name: string;
10792
+ /** @example Comprador */
10793
+ last_name: string;
10794
+ /** @example Teste Comprador */
10795
+ name?: string;
10796
+ /** @example 69526128664 */
10797
+ document?: string;
10798
+ /** @example CPF */
10799
+ document_type?: string;
10800
+ /** @example 99999999900 */
10801
+ checkout_phone?: string;
10802
+ };
10803
+ purchase: {
10804
+ /** @example HP16015479281022 */
10805
+ transaction: string;
10806
+ /** @example APPROVED */
10807
+ status: string;
10808
+ offer?: {
10809
+ /**
10810
+ * @description Offer code used to determine institution assignment
10811
+ * @example d9to7y3w
10812
+ */
10813
+ code?: string;
10814
+ };
10815
+ };
10816
+ product: {
10817
+ id?: number;
10818
+ name?: string;
10819
+ /** Format: uuid */
10820
+ ucode?: string;
10821
+ };
10822
+ subscription?: {
10823
+ subscriber?: {
10824
+ code?: string;
10825
+ };
10826
+ plan?: {
10827
+ name?: string;
10828
+ id?: number;
10829
+ };
10830
+ status?: string;
10831
+ };
10832
+ };
10833
+ };
10834
+ };
10835
+ };
10279
10836
  responses: {
10280
- /** @description User synchronized successfully */
10837
+ /** @description Webhook event processed successfully */
10281
10838
  200: {
10282
10839
  headers: {
10283
10840
  [name: string]: unknown;
@@ -10286,15 +10843,21 @@ interface paths {
10286
10843
  "application/json": {
10287
10844
  /** @example success */
10288
10845
  status?: string;
10289
- data?: components["schemas"]["User"];
10290
- /** @example User synchronized with Keycloak successfully */
10291
- message?: string;
10846
+ /**
10847
+ * @description Action taken for the event
10848
+ * @example user_creation_enqueued
10849
+ * @enum {string}
10850
+ */
10851
+ action?: "user_creation_enqueued" | "user_deactivated" | "user_not_found" | "event_ignored";
10852
+ /**
10853
+ * Format: uuid
10854
+ * @description Request ID for tracking (only on user_creation_enqueued)
10855
+ * @example 550e8400-e29b-41d4-a716-446655440000
10856
+ */
10857
+ requestId?: string;
10292
10858
  };
10293
10859
  };
10294
10860
  };
10295
- 400: components["responses"]["BadRequest"];
10296
- 401: components["responses"]["Unauthorized"];
10297
- 404: components["responses"]["NotFound"];
10298
10861
  500: components["responses"]["ServerError"];
10299
10862
  };
10300
10863
  };
@@ -11549,6 +12112,20 @@ interface components {
11549
12112
  };
11550
12113
  };
11551
12114
  };
12115
+ ForgotPasswordRequest: {
12116
+ /**
12117
+ * Format: email
12118
+ * @description User's email address for password reset
12119
+ * @example user@example.com
12120
+ */
12121
+ email: string;
12122
+ };
12123
+ ForgotPasswordResponse: {
12124
+ /** @example success */
12125
+ status?: string;
12126
+ /** @example If this email is registered, you will receive password reset instructions. */
12127
+ message?: string;
12128
+ };
11552
12129
  CreateInstitutionClassroomDto: {
11553
12130
  /**
11554
12131
  * Format: uuid
@@ -11729,10 +12306,14 @@ interface components {
11729
12306
  * @description Product ID associated with this seat
11730
12307
  */
11731
12308
  productId?: string;
12309
+ /** @description Total number of seat codes for this seat */
12310
+ total?: number;
11732
12311
  /** @description Available quantity for this group in the institution */
11733
12312
  availableQuantity?: number;
11734
12313
  /** @description Number of users currently assigned to this group in the institution */
11735
12314
  usedQuantity?: number;
12315
+ /** @description Number of reserved seat codes without active registration */
12316
+ reservedQuantity?: number;
11736
12317
  /** Format: date-time */
11737
12318
  createdAt?: string;
11738
12319
  /** Format: date-time */
@@ -12221,6 +12802,27 @@ interface components {
12221
12802
  /** Format: uri */
12222
12803
  url?: string;
12223
12804
  };
12805
+ GenerateCertificateDto: {
12806
+ /** Format: uuid */
12807
+ userId: string;
12808
+ /** Format: uuid */
12809
+ quizAttemptId?: string;
12810
+ /** Format: uuid */
12811
+ certificateTemplateId: string;
12812
+ /** @example João Silva */
12813
+ studentName: string;
12814
+ /** @example Introdução ao JavaScript */
12815
+ quizTitle: string;
12816
+ /** @example 85 */
12817
+ score?: number;
12818
+ /** @example CERT-2024-000001 */
12819
+ certificateNumber?: string;
12820
+ /**
12821
+ * Format: date-time
12822
+ * @example 2024-01-01T00:00:00.000Z
12823
+ */
12824
+ issuedAt?: string;
12825
+ };
12224
12826
  CreateGuardianDto: {
12225
12827
  /**
12226
12828
  * Format: email
@@ -13102,6 +13704,7 @@ declare function createUserService(apiClient: AcademeApiClient): {
13102
13704
  requestBody: {
13103
13705
  content: {
13104
13706
  "application/json": {
13707
+ email?: string;
13105
13708
  firstName?: string;
13106
13709
  lastName?: string;
13107
13710
  phone?: string;
@@ -13156,6 +13759,7 @@ declare function createUserService(apiClient: AcademeApiClient): {
13156
13759
  requestBody: {
13157
13760
  content: {
13158
13761
  "application/json": {
13762
+ email?: string;
13159
13763
  firstName?: string;
13160
13764
  lastName?: string;
13161
13765
  phone?: string;
@@ -13406,6 +14010,7 @@ type UpdateCurriculumGridDto = components["schemas"]["UpdateCurriculumGridDto"];
13406
14010
  type CreateCurriculumPeriodDto = components["schemas"]["CreateCurriculumPeriodDto"];
13407
14011
  type UpdateCurriculumPeriodDto = components["schemas"]["UpdateCurriculumPeriodDto"];
13408
14012
  type GetInstitutionUsersQuery = paths["/institutions/{institutionId}/users"]["get"]["parameters"]["query"];
14013
+ type GetInstitutionClassroomsQuery = paths["/institutions/{institutionId}/classrooms"]["get"]["parameters"]["query"];
13409
14014
  declare function createInstitutionService(apiClient: AcademeApiClient): {
13410
14015
  getAll(): Promise<openapi_fetch.FetchResponse<{
13411
14016
  parameters: {
@@ -13721,9 +14326,7 @@ declare function createInstitutionService(apiClient: AcademeApiClient): {
13721
14326
  productId?: string;
13722
14327
  };
13723
14328
  }, `${string}/${string}`>>;
13724
- getClassrooms(institutionId: string, options?: {
13725
- includeUserCount?: boolean;
13726
- }): Promise<openapi_fetch.FetchResponse<{
14329
+ getClassrooms(institutionId: string, options?: GetInstitutionClassroomsQuery): Promise<openapi_fetch.FetchResponse<{
13727
14330
  parameters: {
13728
14331
  query?: {
13729
14332
  includeUserCount?: boolean;
@@ -18516,11 +19119,16 @@ type QuizService = ReturnType<typeof createQuizService>;
18516
19119
 
18517
19120
  type CreateCertificateDto = components["schemas"]["CreateCertificateDto"];
18518
19121
  type UpdateCertificateDto = components["schemas"]["UpdateCertificateDto"];
19122
+ type GenerateCertificateDto = components["schemas"]["GenerateCertificateDto"];
18519
19123
  declare function createCertificateService(apiClient: AcademeApiClient): {
18520
19124
  /**
18521
- * List all certificates
19125
+ * Get current user's certificates
18522
19126
  */
18523
- getMe(): Promise<openapi_fetch.FetchResponse<{
19127
+ getMyCertificates(query?: {
19128
+ search?: string;
19129
+ page?: number;
19130
+ limit?: number;
19131
+ }): Promise<openapi_fetch.FetchResponse<{
18524
19132
  parameters: {
18525
19133
  query?: {
18526
19134
  search?: components["parameters"]["search"];
@@ -18553,12 +19161,32 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18553
19161
  401: components["responses"]["Unauthorized"];
18554
19162
  500: components["responses"]["ServerError"];
18555
19163
  };
18556
- }, openapi_fetch.FetchOptions<{
19164
+ }, {
19165
+ params: {
19166
+ query: {
19167
+ search?: string;
19168
+ page?: number;
19169
+ limit?: number;
19170
+ } | undefined;
19171
+ };
19172
+ }, `${string}/${string}`>>;
19173
+ /**
19174
+ * List all certificates
19175
+ */
19176
+ getAll(query?: {
19177
+ userId?: string;
19178
+ search?: string;
19179
+ page?: number;
19180
+ limit?: number;
19181
+ includeCourse?: boolean;
19182
+ }): Promise<openapi_fetch.FetchResponse<{
18557
19183
  parameters: {
18558
19184
  query?: {
19185
+ userId?: string;
18559
19186
  search?: components["parameters"]["search"];
18560
19187
  page?: components["parameters"]["page"];
18561
19188
  limit?: components["parameters"]["limit"];
19189
+ includeCourse?: boolean;
18562
19190
  };
18563
19191
  header?: never;
18564
19192
  path?: never;
@@ -18586,12 +19214,27 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18586
19214
  401: components["responses"]["Unauthorized"];
18587
19215
  500: components["responses"]["ServerError"];
18588
19216
  };
18589
- }> | undefined, `${string}/${string}`>>;
18590
- getAll(): Promise<openapi_fetch.FetchResponse<{
19217
+ }, {
19218
+ params: {
19219
+ query: {
19220
+ userId?: string;
19221
+ search?: string;
19222
+ page?: number;
19223
+ limit?: number;
19224
+ includeCourse?: boolean;
19225
+ } | undefined;
19226
+ };
19227
+ }, `${string}/${string}`>>;
19228
+ /**
19229
+ * Get certificate by ID
19230
+ */
19231
+ getById(id: string): Promise<openapi_fetch.FetchResponse<{
18591
19232
  parameters: {
18592
19233
  query?: never;
18593
19234
  header?: never;
18594
- path?: never;
19235
+ path: {
19236
+ id: components["parameters"]["id"];
19237
+ };
18595
19238
  cookie?: never;
18596
19239
  };
18597
19240
  requestBody?: never;
@@ -18603,90 +19246,71 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18603
19246
  content: {
18604
19247
  "application/json": {
18605
19248
  status?: string;
18606
- data?: components["schemas"]["Certificate"][];
19249
+ data?: components["schemas"]["Certificate"];
18607
19250
  };
18608
19251
  };
18609
19252
  };
19253
+ 400: components["responses"]["BadRequest"];
18610
19254
  401: components["responses"]["Unauthorized"];
19255
+ 404: components["responses"]["NotFound"];
18611
19256
  500: components["responses"]["ServerError"];
18612
19257
  };
18613
- }, openapi_fetch.FetchOptions<{
19258
+ }, {
19259
+ params: {
19260
+ path: {
19261
+ id: string;
19262
+ };
19263
+ };
19264
+ }, `${string}/${string}`>>;
19265
+ /**
19266
+ * Download all certificates of a given user as a single merged PDF
19267
+ */
19268
+ downloadAll(userId: string): Promise<openapi_fetch.FetchResponse<{
18614
19269
  parameters: {
18615
19270
  query?: never;
18616
19271
  header?: never;
18617
- path?: never;
19272
+ path: {
19273
+ userId: string;
19274
+ };
18618
19275
  cookie?: never;
18619
19276
  };
18620
19277
  requestBody?: never;
18621
19278
  responses: {
18622
19279
  200: {
18623
19280
  headers: {
19281
+ "Content-Disposition"?: string;
18624
19282
  [name: string]: unknown;
18625
19283
  };
18626
19284
  content: {
18627
- "application/json": {
18628
- status?: string;
18629
- data?: components["schemas"]["Certificate"][];
18630
- };
19285
+ "application/pdf": string;
18631
19286
  };
18632
19287
  };
18633
19288
  401: components["responses"]["Unauthorized"];
18634
- 500: components["responses"]["ServerError"];
18635
- };
18636
- }> | undefined, `${string}/${string}`>>;
18637
- /**
18638
- * Get current user's certificates
18639
- */
18640
- getMyCertificates(query?: {
18641
- search?: string;
18642
- page?: number;
18643
- limit?: number;
18644
- }): Promise<openapi_fetch.FetchResponse<{
18645
- parameters: {
18646
- query?: {
18647
- search?: components["parameters"]["search"];
18648
- page?: components["parameters"]["page"];
18649
- limit?: components["parameters"]["limit"];
18650
- };
18651
- header?: never;
18652
- path?: never;
18653
- cookie?: never;
18654
- };
18655
- requestBody?: never;
18656
- responses: {
18657
- 200: {
19289
+ 404: {
18658
19290
  headers: {
18659
19291
  [name: string]: unknown;
18660
19292
  };
18661
19293
  content: {
18662
19294
  "application/json": {
18663
19295
  status?: string;
18664
- data?: components["schemas"]["Certificate"][];
18665
- meta?: {
18666
- total?: number;
18667
- page?: number;
18668
- limit?: number;
18669
- totalPages?: number;
18670
- };
19296
+ message?: string;
18671
19297
  };
18672
19298
  };
18673
19299
  };
18674
- 401: components["responses"]["Unauthorized"];
18675
19300
  500: components["responses"]["ServerError"];
18676
19301
  };
18677
19302
  }, {
18678
19303
  params: {
18679
- query: {
18680
- search?: string;
18681
- page?: number;
18682
- limit?: number;
18683
- } | undefined;
19304
+ path: {
19305
+ userId: string;
19306
+ };
18684
19307
  };
19308
+ parseAs: "blob";
18685
19309
  }, `${string}/${string}`>>;
18686
19310
  /**
18687
- * Get certificate by ID
19311
+ * Download certificate PDF
18688
19312
  */
18689
- getById(id: string): Promise<openapi_fetch.FetchResponse<{
19313
+ download(id: string): Promise<openapi_fetch.FetchResponse<{
18690
19314
  parameters: {
18691
19315
  query?: never;
18692
19316
  header?: never;
@@ -18702,14 +19326,11 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18702
19326
  [name: string]: unknown;
18703
19327
  };
18704
19328
  content: {
18705
- "application/json": {
18706
- status?: string;
18707
- data?: components["schemas"]["Certificate"];
18708
- };
19329
+ "application/pdf": string;
18709
19330
  };
18710
19331
  };
18711
- 400: components["responses"]["BadRequest"];
18712
19332
  401: components["responses"]["Unauthorized"];
19333
+ 403: components["responses"]["Forbidden"];
18713
19334
  404: components["responses"]["NotFound"];
18714
19335
  500: components["responses"]["ServerError"];
18715
19336
  };
@@ -18744,7 +19365,6 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18744
19365
  "application/json": {
18745
19366
  status?: string;
18746
19367
  data?: components["schemas"]["Certificate"];
18747
- message?: string;
18748
19368
  };
18749
19369
  };
18750
19370
  };
@@ -18761,6 +19381,52 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18761
19381
  url?: string;
18762
19382
  };
18763
19383
  }, `${string}/${string}`>>;
19384
+ /**
19385
+ * Generate a certificate PDF server-side
19386
+ */
19387
+ generate(data: GenerateCertificateDto): Promise<openapi_fetch.FetchResponse<{
19388
+ parameters: {
19389
+ query?: never;
19390
+ header?: never;
19391
+ path?: never;
19392
+ cookie?: never;
19393
+ };
19394
+ requestBody: {
19395
+ content: {
19396
+ "application/json": components["schemas"]["GenerateCertificateDto"];
19397
+ };
19398
+ };
19399
+ responses: {
19400
+ 201: {
19401
+ headers: {
19402
+ [name: string]: unknown;
19403
+ };
19404
+ content: {
19405
+ "application/json": {
19406
+ status?: string;
19407
+ data?: {
19408
+ certificate?: components["schemas"]["Certificate"];
19409
+ pdfUrl?: string;
19410
+ };
19411
+ };
19412
+ };
19413
+ };
19414
+ 400: components["responses"]["BadRequest"];
19415
+ 401: components["responses"]["Unauthorized"];
19416
+ 500: components["responses"]["ServerError"];
19417
+ };
19418
+ }, {
19419
+ body: {
19420
+ userId: string;
19421
+ quizAttemptId?: string;
19422
+ certificateTemplateId: string;
19423
+ studentName: string;
19424
+ quizTitle: string;
19425
+ score?: number;
19426
+ certificateNumber?: string;
19427
+ issuedAt?: string;
19428
+ };
19429
+ }, `${string}/${string}`>>;
18764
19430
  /**
18765
19431
  * Update certificate
18766
19432
  */
@@ -18787,7 +19453,6 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18787
19453
  "application/json": {
18788
19454
  status?: string;
18789
19455
  data?: components["schemas"]["Certificate"];
18790
- message?: string;
18791
19456
  };
18792
19457
  };
18793
19458
  };
@@ -18823,16 +19488,11 @@ declare function createCertificateService(apiClient: AcademeApiClient): {
18823
19488
  };
18824
19489
  requestBody?: never;
18825
19490
  responses: {
18826
- 200: {
19491
+ 204: {
18827
19492
  headers: {
18828
19493
  [name: string]: unknown;
18829
19494
  };
18830
- content: {
18831
- "application/json": {
18832
- status?: string;
18833
- message?: string;
18834
- };
18835
- };
19495
+ content?: never;
18836
19496
  };
18837
19497
  400: components["responses"]["BadRequest"];
18838
19498
  401: components["responses"]["Unauthorized"];