Spaces:
Running
Running
Commit ·
f18c71f
1
Parent(s): 92a54e4
Deploy files from GitHub repository
Browse files- Quzuu_API_Collection.postman_collection.json +1099 -499
- controllers/academy_controller.go +123 -11
- controllers/admin_academy_controller.go +342 -0
- controllers/admin_statistic_controller.go +231 -0
- controllers/controller.go +15 -2
- models/dto/academy_dto.go +11 -0
- models/dto/admin_statistic_dto.go +137 -0
- provider/controller_provider.go +105 -89
- provider/repositories_provider.go +266 -250
- provider/services_provider.go +159 -143
- repositories/academy_repository.go +6 -0
- repositories/admin_academy_repository.go +208 -0
- repositories/admin_statistic_repository.go +524 -0
- router/admin_academy_router.go +37 -0
- router/admin_router.go +0 -20
- router/admin_statistic_router.go +34 -0
- router/router.go +2 -0
- services/academy_service.go +53 -0
- services/admin_academy_service.go +404 -0
- services/admin_statistic_service.go +97 -0
Quzuu_API_Collection.postman_collection.json
CHANGED
|
@@ -977,6 +977,634 @@
|
|
| 977 |
"description": "Update progress on academy content"
|
| 978 |
},
|
| 979 |
"response": []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 980 |
}
|
| 981 |
]
|
| 982 |
},
|
|
@@ -1414,10 +2042,10 @@
|
|
| 1414 |
"name": "Admin",
|
| 1415 |
"item": [
|
| 1416 |
{
|
| 1417 |
-
"name": "Admin
|
| 1418 |
"item": [
|
| 1419 |
{
|
| 1420 |
-
"name": "
|
| 1421 |
"request": {
|
| 1422 |
"method": "GET",
|
| 1423 |
"header": [
|
|
@@ -1428,7 +2056,7 @@
|
|
| 1428 |
}
|
| 1429 |
],
|
| 1430 |
"url": {
|
| 1431 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1432 |
"host": [
|
| 1433 |
"{{base_url}}"
|
| 1434 |
],
|
|
@@ -1436,63 +2064,26 @@
|
|
| 1436 |
"api",
|
| 1437 |
"v1",
|
| 1438 |
"admin",
|
| 1439 |
-
"
|
| 1440 |
-
""
|
| 1441 |
-
],
|
| 1442 |
-
"query": [
|
| 1443 |
-
{
|
| 1444 |
-
"key": "page",
|
| 1445 |
-
"value": "1"
|
| 1446 |
-
},
|
| 1447 |
-
{
|
| 1448 |
-
"key": "limit",
|
| 1449 |
-
"value": "10"
|
| 1450 |
-
},
|
| 1451 |
-
{
|
| 1452 |
-
"key": "search",
|
| 1453 |
-
"value": ""
|
| 1454 |
-
},
|
| 1455 |
-
{
|
| 1456 |
-
"key": "sortBy",
|
| 1457 |
-
"value": "created_at"
|
| 1458 |
-
},
|
| 1459 |
-
{
|
| 1460 |
-
"key": "order",
|
| 1461 |
-
"value": "desc"
|
| 1462 |
-
},
|
| 1463 |
-
{
|
| 1464 |
-
"key": "status",
|
| 1465 |
-
"value": "",
|
| 1466 |
-
"disabled": true
|
| 1467 |
-
}
|
| 1468 |
]
|
| 1469 |
-
}
|
| 1470 |
-
"description": "Admin view: list all events with participant_count and exam_count. Supports pagination and search."
|
| 1471 |
},
|
| 1472 |
"response": []
|
| 1473 |
},
|
| 1474 |
{
|
| 1475 |
-
"name": "
|
| 1476 |
"request": {
|
| 1477 |
-
"method": "
|
| 1478 |
"header": [
|
| 1479 |
-
{
|
| 1480 |
-
"key": "Content-Type",
|
| 1481 |
-
"value": "application/json",
|
| 1482 |
-
"type": "text"
|
| 1483 |
-
},
|
| 1484 |
{
|
| 1485 |
"key": "Authorization",
|
| 1486 |
"value": "Bearer {{access_token}}",
|
| 1487 |
"type": "text"
|
| 1488 |
}
|
| 1489 |
],
|
| 1490 |
-
"body": {
|
| 1491 |
-
"mode": "raw",
|
| 1492 |
-
"raw": "{\n \"title\": \"National Olympiad 2026\",\n \"start_event\": \"2026-04-01T08:00:00Z\",\n \"end_event\": \"2026-04-02T17:00:00Z\",\n \"overview\": \"Annual national programming olympiad\",\n \"img_banner\": \"https://example.com/banner.jpg\",\n \"event_code\": \"NAT2026\",\n \"is_public\": true\n}"
|
| 1493 |
-
},
|
| 1494 |
"url": {
|
| 1495 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1496 |
"host": [
|
| 1497 |
"{{base_url}}"
|
| 1498 |
],
|
|
@@ -1500,36 +2091,32 @@
|
|
| 1500 |
"api",
|
| 1501 |
"v1",
|
| 1502 |
"admin",
|
| 1503 |
-
"
|
| 1504 |
-
""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1505 |
]
|
| 1506 |
-
}
|
| 1507 |
-
"description": "Create a new event."
|
| 1508 |
},
|
| 1509 |
"response": []
|
| 1510 |
},
|
| 1511 |
{
|
| 1512 |
-
"name": "
|
| 1513 |
"request": {
|
| 1514 |
-
"method": "
|
| 1515 |
"header": [
|
| 1516 |
-
{
|
| 1517 |
-
"key": "Content-Type",
|
| 1518 |
-
"value": "application/json",
|
| 1519 |
-
"type": "text"
|
| 1520 |
-
},
|
| 1521 |
{
|
| 1522 |
"key": "Authorization",
|
| 1523 |
"value": "Bearer {{access_token}}",
|
| 1524 |
"type": "text"
|
| 1525 |
}
|
| 1526 |
],
|
| 1527 |
-
"body": {
|
| 1528 |
-
"mode": "raw",
|
| 1529 |
-
"raw": "{\n \"title\": \"Updated Event Title\",\n \"overview\": \"Updated overview text\",\n \"is_public\": true\n}"
|
| 1530 |
-
},
|
| 1531 |
"url": {
|
| 1532 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1533 |
"host": [
|
| 1534 |
"{{base_url}}"
|
| 1535 |
],
|
|
@@ -1537,24 +2124,17 @@
|
|
| 1537 |
"api",
|
| 1538 |
"v1",
|
| 1539 |
"admin",
|
| 1540 |
-
"
|
| 1541 |
-
"
|
| 1542 |
-
],
|
| 1543 |
-
"variable": [
|
| 1544 |
-
{
|
| 1545 |
-
"key": "event_id",
|
| 1546 |
-
"value": "{{event_id}}"
|
| 1547 |
-
}
|
| 1548 |
]
|
| 1549 |
-
}
|
| 1550 |
-
"description": "Update an existing event by ID."
|
| 1551 |
},
|
| 1552 |
"response": []
|
| 1553 |
},
|
| 1554 |
{
|
| 1555 |
-
"name": "
|
| 1556 |
"request": {
|
| 1557 |
-
"method": "
|
| 1558 |
"header": [
|
| 1559 |
{
|
| 1560 |
"key": "Authorization",
|
|
@@ -1563,7 +2143,7 @@
|
|
| 1563 |
}
|
| 1564 |
],
|
| 1565 |
"url": {
|
| 1566 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1567 |
"host": [
|
| 1568 |
"{{base_url}}"
|
| 1569 |
],
|
|
@@ -1571,7 +2151,8 @@
|
|
| 1571 |
"api",
|
| 1572 |
"v1",
|
| 1573 |
"admin",
|
| 1574 |
-
"
|
|
|
|
| 1575 |
":event_id"
|
| 1576 |
],
|
| 1577 |
"variable": [
|
|
@@ -1580,13 +2161,12 @@
|
|
| 1580 |
"value": "{{event_id}}"
|
| 1581 |
}
|
| 1582 |
]
|
| 1583 |
-
}
|
| 1584 |
-
"description": "Delete an event by ID."
|
| 1585 |
},
|
| 1586 |
"response": []
|
| 1587 |
},
|
| 1588 |
{
|
| 1589 |
-
"name": "
|
| 1590 |
"request": {
|
| 1591 |
"method": "GET",
|
| 1592 |
"header": [
|
|
@@ -1594,61 +2174,26 @@
|
|
| 1594 |
"key": "Authorization",
|
| 1595 |
"value": "Bearer {{access_token}}",
|
| 1596 |
"type": "text"
|
| 1597 |
-
}
|
| 1598 |
-
],
|
| 1599 |
-
"url": {
|
| 1600 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1601 |
-
"host": [
|
| 1602 |
-
"{{base_url}}"
|
| 1603 |
-
],
|
| 1604 |
-
"path": [
|
| 1605 |
-
"api",
|
| 1606 |
-
"v1",
|
| 1607 |
-
"admin",
|
| 1608 |
-
"
|
| 1609 |
-
"
|
| 1610 |
-
"participants"
|
| 1611 |
-
],
|
| 1612 |
-
"variable": [
|
| 1613 |
-
{
|
| 1614 |
-
"key": "event_id",
|
| 1615 |
-
"value": "{{event_id}}"
|
| 1616 |
-
}
|
| 1617 |
-
],
|
| 1618 |
-
"query": [
|
| 1619 |
-
{
|
| 1620 |
-
"key": "page",
|
| 1621 |
-
"value": "1",
|
| 1622 |
-
"description": "Page number"
|
| 1623 |
-
},
|
| 1624 |
-
{
|
| 1625 |
-
"key": "limit",
|
| 1626 |
-
"value": "10",
|
| 1627 |
-
"description": "Items per page (max 100)"
|
| 1628 |
-
},
|
| 1629 |
-
{
|
| 1630 |
-
"key": "search",
|
| 1631 |
-
"value": "",
|
| 1632 |
-
"description": "Search by username / full name"
|
| 1633 |
-
},
|
| 1634 |
-
{
|
| 1635 |
-
"key": "sortBy",
|
| 1636 |
-
"value": "assigned_at",
|
| 1637 |
-
"description": "Sort field (assigned_at, username, full_name)"
|
| 1638 |
-
},
|
| 1639 |
-
{
|
| 1640 |
-
"key": "order",
|
| 1641 |
-
"value": "desc",
|
| 1642 |
-
"description": "Sort direction (asc / desc)"
|
| 1643 |
-
}
|
| 1644 |
]
|
| 1645 |
-
}
|
| 1646 |
-
"description": "List all participants (with account details) assigned to an event."
|
| 1647 |
},
|
| 1648 |
"response": []
|
| 1649 |
},
|
| 1650 |
{
|
| 1651 |
-
"name": "
|
| 1652 |
"request": {
|
| 1653 |
"method": "GET",
|
| 1654 |
"header": [
|
|
@@ -1659,7 +2204,7 @@
|
|
| 1659 |
}
|
| 1660 |
],
|
| 1661 |
"url": {
|
| 1662 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1663 |
"host": [
|
| 1664 |
"{{base_url}}"
|
| 1665 |
],
|
|
@@ -1667,70 +2212,60 @@
|
|
| 1667 |
"api",
|
| 1668 |
"v1",
|
| 1669 |
"admin",
|
| 1670 |
-
"
|
| 1671 |
-
"
|
| 1672 |
-
"
|
| 1673 |
],
|
| 1674 |
"variable": [
|
| 1675 |
{
|
| 1676 |
-
"key": "
|
| 1677 |
-
"value": "{{
|
| 1678 |
-
}
|
| 1679 |
-
],
|
| 1680 |
-
"query": [
|
| 1681 |
-
{
|
| 1682 |
-
"key": "page",
|
| 1683 |
-
"value": "1",
|
| 1684 |
-
"description": "Page number"
|
| 1685 |
-
},
|
| 1686 |
-
{
|
| 1687 |
-
"key": "limit",
|
| 1688 |
-
"value": "10",
|
| 1689 |
-
"description": "Items per page (max 100)"
|
| 1690 |
-
},
|
| 1691 |
-
{
|
| 1692 |
-
"key": "search",
|
| 1693 |
-
"value": "",
|
| 1694 |
-
"description": "Search by username / full name"
|
| 1695 |
-
},
|
| 1696 |
-
{
|
| 1697 |
-
"key": "sortBy",
|
| 1698 |
-
"value": "created_at",
|
| 1699 |
-
"description": "Sort field (username, full_name, created_at)"
|
| 1700 |
-
},
|
| 1701 |
-
{
|
| 1702 |
-
"key": "orderBy",
|
| 1703 |
-
"value": "desc",
|
| 1704 |
-
"description": "Sort direction (asc / desc)"
|
| 1705 |
}
|
| 1706 |
]
|
| 1707 |
-
}
|
| 1708 |
-
"description": "List accounts that are not yet assigned to the event."
|
| 1709 |
},
|
| 1710 |
"response": []
|
| 1711 |
},
|
| 1712 |
{
|
| 1713 |
-
"name": "
|
| 1714 |
"request": {
|
| 1715 |
-
"method": "
|
| 1716 |
"header": [
|
| 1717 |
{
|
| 1718 |
-
"key": "
|
| 1719 |
-
"value": "
|
| 1720 |
"type": "text"
|
| 1721 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1722 |
{
|
| 1723 |
"key": "Authorization",
|
| 1724 |
"value": "Bearer {{access_token}}",
|
| 1725 |
"type": "text"
|
| 1726 |
}
|
| 1727 |
],
|
| 1728 |
-
"body": {
|
| 1729 |
-
"mode": "raw",
|
| 1730 |
-
"raw": "{\n \"user_id\": \"{{user_id}}\"\n}"
|
| 1731 |
-
},
|
| 1732 |
"url": {
|
| 1733 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1734 |
"host": [
|
| 1735 |
"{{base_url}}"
|
| 1736 |
],
|
|
@@ -1738,25 +2273,24 @@
|
|
| 1738 |
"api",
|
| 1739 |
"v1",
|
| 1740 |
"admin",
|
| 1741 |
-
"
|
| 1742 |
-
"
|
| 1743 |
-
"
|
| 1744 |
],
|
| 1745 |
"variable": [
|
| 1746 |
{
|
| 1747 |
-
"key": "
|
| 1748 |
-
"value": "{{
|
| 1749 |
}
|
| 1750 |
]
|
| 1751 |
-
}
|
| 1752 |
-
"description": "Manually assign a user to an event. Bypasses payment."
|
| 1753 |
},
|
| 1754 |
"response": []
|
| 1755 |
},
|
| 1756 |
{
|
| 1757 |
-
"name": "
|
| 1758 |
"request": {
|
| 1759 |
-
"method": "
|
| 1760 |
"header": [
|
| 1761 |
{
|
| 1762 |
"key": "Authorization",
|
|
@@ -1765,7 +2299,7 @@
|
|
| 1765 |
}
|
| 1766 |
],
|
| 1767 |
"url": {
|
| 1768 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1769 |
"host": [
|
| 1770 |
"{{base_url}}"
|
| 1771 |
],
|
|
@@ -1773,28 +2307,15 @@
|
|
| 1773 |
"api",
|
| 1774 |
"v1",
|
| 1775 |
"admin",
|
| 1776 |
-
"
|
| 1777 |
-
"
|
| 1778 |
-
"participants",
|
| 1779 |
-
":user_id"
|
| 1780 |
-
],
|
| 1781 |
-
"variable": [
|
| 1782 |
-
{
|
| 1783 |
-
"key": "event_id",
|
| 1784 |
-
"value": "{{event_id}}"
|
| 1785 |
-
},
|
| 1786 |
-
{
|
| 1787 |
-
"key": "user_id",
|
| 1788 |
-
"value": "{{user_id}}"
|
| 1789 |
-
}
|
| 1790 |
]
|
| 1791 |
-
}
|
| 1792 |
-
"description": "Unassign a user from an event."
|
| 1793 |
},
|
| 1794 |
"response": []
|
| 1795 |
},
|
| 1796 |
{
|
| 1797 |
-
"name": "
|
| 1798 |
"request": {
|
| 1799 |
"method": "GET",
|
| 1800 |
"header": [
|
|
@@ -1805,7 +2326,7 @@
|
|
| 1805 |
}
|
| 1806 |
],
|
| 1807 |
"url": {
|
| 1808 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1809 |
"host": [
|
| 1810 |
"{{base_url}}"
|
| 1811 |
],
|
|
@@ -1813,50 +2334,22 @@
|
|
| 1813 |
"api",
|
| 1814 |
"v1",
|
| 1815 |
"admin",
|
| 1816 |
-
"
|
| 1817 |
-
"
|
| 1818 |
-
"
|
| 1819 |
],
|
| 1820 |
"variable": [
|
| 1821 |
{
|
| 1822 |
-
"key": "
|
| 1823 |
-
"value": "{{
|
| 1824 |
-
}
|
| 1825 |
-
],
|
| 1826 |
-
"query": [
|
| 1827 |
-
{
|
| 1828 |
-
"key": "page",
|
| 1829 |
-
"value": "1",
|
| 1830 |
-
"description": "Page number"
|
| 1831 |
-
},
|
| 1832 |
-
{
|
| 1833 |
-
"key": "limit",
|
| 1834 |
-
"value": "10",
|
| 1835 |
-
"description": "Items per page (max 100)"
|
| 1836 |
-
},
|
| 1837 |
-
{
|
| 1838 |
-
"key": "search",
|
| 1839 |
-
"value": "",
|
| 1840 |
-
"description": "Search term"
|
| 1841 |
-
},
|
| 1842 |
-
{
|
| 1843 |
-
"key": "sortBy",
|
| 1844 |
-
"value": "created_at",
|
| 1845 |
-
"description": "Sort field (title, slug, created_at, duration)"
|
| 1846 |
-
},
|
| 1847 |
-
{
|
| 1848 |
-
"key": "order",
|
| 1849 |
-
"value": "desc",
|
| 1850 |
-
"description": "Sort direction (asc / desc)"
|
| 1851 |
}
|
| 1852 |
]
|
| 1853 |
-
}
|
| 1854 |
-
"description": "List all exams assigned to an event, with exam details."
|
| 1855 |
},
|
| 1856 |
"response": []
|
| 1857 |
},
|
| 1858 |
{
|
| 1859 |
-
"name": "
|
| 1860 |
"request": {
|
| 1861 |
"method": "GET",
|
| 1862 |
"header": [
|
|
@@ -1867,7 +2360,7 @@
|
|
| 1867 |
}
|
| 1868 |
],
|
| 1869 |
"url": {
|
| 1870 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1871 |
"host": [
|
| 1872 |
"{{base_url}}"
|
| 1873 |
],
|
|
@@ -1875,53 +2368,17 @@
|
|
| 1875 |
"api",
|
| 1876 |
"v1",
|
| 1877 |
"admin",
|
| 1878 |
-
"
|
| 1879 |
-
"
|
| 1880 |
-
"exams",
|
| 1881 |
-
"candidate"
|
| 1882 |
-
],
|
| 1883 |
-
"variable": [
|
| 1884 |
-
{
|
| 1885 |
-
"key": "event_id",
|
| 1886 |
-
"value": "{{event_id}}"
|
| 1887 |
-
}
|
| 1888 |
-
],
|
| 1889 |
-
"query": [
|
| 1890 |
-
{
|
| 1891 |
-
"key": "page",
|
| 1892 |
-
"value": "1",
|
| 1893 |
-
"description": "Page number"
|
| 1894 |
-
},
|
| 1895 |
-
{
|
| 1896 |
-
"key": "limit",
|
| 1897 |
-
"value": "10",
|
| 1898 |
-
"description": "Items per page (max 100)"
|
| 1899 |
-
},
|
| 1900 |
-
{
|
| 1901 |
-
"key": "search",
|
| 1902 |
-
"value": "",
|
| 1903 |
-
"description": "Search by exam title / slug"
|
| 1904 |
-
},
|
| 1905 |
-
{
|
| 1906 |
-
"key": "sortBy",
|
| 1907 |
-
"value": "created_at",
|
| 1908 |
-
"description": "Sort field (title, slug, created_at, duration)"
|
| 1909 |
-
},
|
| 1910 |
-
{
|
| 1911 |
-
"key": "orderBy",
|
| 1912 |
-
"value": "desc",
|
| 1913 |
-
"description": "Sort direction (asc / desc)"
|
| 1914 |
-
}
|
| 1915 |
]
|
| 1916 |
-
}
|
| 1917 |
-
"description": "List exams that are not yet assigned to the event."
|
| 1918 |
},
|
| 1919 |
"response": []
|
| 1920 |
},
|
| 1921 |
{
|
| 1922 |
-
"name": "
|
| 1923 |
"request": {
|
| 1924 |
-
"method": "
|
| 1925 |
"header": [
|
| 1926 |
{
|
| 1927 |
"key": "Authorization",
|
|
@@ -1930,7 +2387,7 @@
|
|
| 1930 |
}
|
| 1931 |
],
|
| 1932 |
"url": {
|
| 1933 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 1934 |
"host": [
|
| 1935 |
"{{base_url}}"
|
| 1936 |
],
|
|
@@ -1938,28 +2395,27 @@
|
|
| 1938 |
"api",
|
| 1939 |
"v1",
|
| 1940 |
"admin",
|
| 1941 |
-
"
|
| 1942 |
-
"
|
| 1943 |
-
"
|
| 1944 |
-
":exam_id"
|
| 1945 |
],
|
| 1946 |
"variable": [
|
| 1947 |
{
|
| 1948 |
-
"key": "
|
| 1949 |
-
"value": "{{
|
| 1950 |
-
},
|
| 1951 |
-
{
|
| 1952 |
-
"key": "exam_id",
|
| 1953 |
-
"value": "{{exam_id}}"
|
| 1954 |
}
|
| 1955 |
]
|
| 1956 |
-
}
|
| 1957 |
-
"description": "Unassign an exam from an event."
|
| 1958 |
},
|
| 1959 |
"response": []
|
| 1960 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1961 |
{
|
| 1962 |
-
"name": "
|
| 1963 |
"request": {
|
| 1964 |
"method": "GET",
|
| 1965 |
"header": [
|
|
@@ -1970,7 +2426,7 @@
|
|
| 1970 |
}
|
| 1971 |
],
|
| 1972 |
"url": {
|
| 1973 |
-
"raw": "{{base_url}}/api/v1/admin/events/
|
| 1974 |
"host": [
|
| 1975 |
"{{base_url}}"
|
| 1976 |
],
|
|
@@ -1979,57 +2435,44 @@
|
|
| 1979 |
"v1",
|
| 1980 |
"admin",
|
| 1981 |
"events",
|
| 1982 |
-
"
|
| 1983 |
-
"exams",
|
| 1984 |
-
":exam_id",
|
| 1985 |
-
"results"
|
| 1986 |
-
],
|
| 1987 |
-
"variable": [
|
| 1988 |
-
{
|
| 1989 |
-
"key": "event_id",
|
| 1990 |
-
"value": "{{event_id}}"
|
| 1991 |
-
},
|
| 1992 |
-
{
|
| 1993 |
-
"key": "exam_id",
|
| 1994 |
-
"value": "{{exam_id}}"
|
| 1995 |
-
}
|
| 1996 |
],
|
| 1997 |
"query": [
|
| 1998 |
{
|
| 1999 |
"key": "page",
|
| 2000 |
-
"value": "1"
|
| 2001 |
-
"description": "Page number"
|
| 2002 |
},
|
| 2003 |
{
|
| 2004 |
"key": "limit",
|
| 2005 |
-
"value": "10"
|
| 2006 |
-
"description": "Items per page (max 100)"
|
| 2007 |
},
|
| 2008 |
{
|
| 2009 |
"key": "search",
|
| 2010 |
-
"value": ""
|
| 2011 |
-
"description": "Search by username / full name"
|
| 2012 |
},
|
| 2013 |
{
|
| 2014 |
"key": "sortBy",
|
| 2015 |
-
"value": "
|
| 2016 |
-
"description": "Sort field (final_score, created_at, username, full_name)"
|
| 2017 |
},
|
| 2018 |
{
|
| 2019 |
"key": "order",
|
| 2020 |
-
"value": "desc"
|
| 2021 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2022 |
}
|
| 2023 |
]
|
| 2024 |
},
|
| 2025 |
-
"description": "
|
| 2026 |
},
|
| 2027 |
"response": []
|
| 2028 |
},
|
| 2029 |
{
|
| 2030 |
-
"name": "
|
| 2031 |
"request": {
|
| 2032 |
-
"method": "
|
| 2033 |
"header": [
|
| 2034 |
{
|
| 2035 |
"key": "Content-Type",
|
|
@@ -2044,10 +2487,10 @@
|
|
| 2044 |
],
|
| 2045 |
"body": {
|
| 2046 |
"mode": "raw",
|
| 2047 |
-
"raw": "{\n \"
|
| 2048 |
},
|
| 2049 |
"url": {
|
| 2050 |
-
"raw": "{{base_url}}/api/v1/admin/events/
|
| 2051 |
"host": [
|
| 2052 |
"{{base_url}}"
|
| 2053 |
],
|
|
@@ -2056,44 +2499,35 @@
|
|
| 2056 |
"v1",
|
| 2057 |
"admin",
|
| 2058 |
"events",
|
| 2059 |
-
"
|
| 2060 |
-
"exams",
|
| 2061 |
-
":exam_id",
|
| 2062 |
-
"results",
|
| 2063 |
-
":result_id"
|
| 2064 |
-
],
|
| 2065 |
-
"variable": [
|
| 2066 |
-
{
|
| 2067 |
-
"key": "event_id",
|
| 2068 |
-
"value": "{{event_id}}"
|
| 2069 |
-
},
|
| 2070 |
-
{
|
| 2071 |
-
"key": "exam_id",
|
| 2072 |
-
"value": "{{exam_id}}"
|
| 2073 |
-
},
|
| 2074 |
-
{
|
| 2075 |
-
"key": "result_id",
|
| 2076 |
-
"value": "{{result_id}}"
|
| 2077 |
-
}
|
| 2078 |
]
|
| 2079 |
},
|
| 2080 |
-
"description": "
|
| 2081 |
},
|
| 2082 |
"response": []
|
| 2083 |
},
|
| 2084 |
{
|
| 2085 |
-
"name": "
|
| 2086 |
"request": {
|
| 2087 |
-
"method": "
|
| 2088 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2089 |
{
|
| 2090 |
"key": "Authorization",
|
| 2091 |
"value": "Bearer {{access_token}}",
|
| 2092 |
"type": "text"
|
| 2093 |
}
|
| 2094 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2095 |
"url": {
|
| 2096 |
-
"raw": "{{base_url}}/api/v1/admin/events/:event_id
|
| 2097 |
"host": [
|
| 2098 |
"{{base_url}}"
|
| 2099 |
],
|
|
@@ -2102,58 +2536,32 @@
|
|
| 2102 |
"v1",
|
| 2103 |
"admin",
|
| 2104 |
"events",
|
| 2105 |
-
":event_id"
|
| 2106 |
-
"exams",
|
| 2107 |
-
":exam_id",
|
| 2108 |
-
"results",
|
| 2109 |
-
":result_id"
|
| 2110 |
],
|
| 2111 |
"variable": [
|
| 2112 |
{
|
| 2113 |
"key": "event_id",
|
| 2114 |
"value": "{{event_id}}"
|
| 2115 |
-
},
|
| 2116 |
-
{
|
| 2117 |
-
"key": "exam_id",
|
| 2118 |
-
"value": "{{exam_id}}"
|
| 2119 |
-
},
|
| 2120 |
-
{
|
| 2121 |
-
"key": "result_id",
|
| 2122 |
-
"value": "{{result_id}}"
|
| 2123 |
}
|
| 2124 |
]
|
| 2125 |
},
|
| 2126 |
-
"description": "
|
| 2127 |
},
|
| 2128 |
"response": []
|
| 2129 |
-
}
|
| 2130 |
-
]
|
| 2131 |
-
},
|
| 2132 |
-
{
|
| 2133 |
-
"name": "Academy Management",
|
| 2134 |
-
"item": [
|
| 2135 |
{
|
| 2136 |
-
"name": "
|
| 2137 |
"request": {
|
| 2138 |
-
"method": "
|
| 2139 |
"header": [
|
| 2140 |
-
{
|
| 2141 |
-
"key": "Content-Type",
|
| 2142 |
-
"value": "application/json",
|
| 2143 |
-
"type": "text"
|
| 2144 |
-
},
|
| 2145 |
{
|
| 2146 |
"key": "Authorization",
|
| 2147 |
"value": "Bearer {{access_token}}",
|
| 2148 |
"type": "text"
|
| 2149 |
}
|
| 2150 |
],
|
| 2151 |
-
"body": {
|
| 2152 |
-
"mode": "raw",
|
| 2153 |
-
"raw": "{\n \"title\": \"Academy Title\",\n \"slug\": \"academy-slug\",\n \"code\": \"ACAD01\",\n \"is_public\": true,\n \"description\": \"Academy description\",\n \"image_url\": \"https://example.com/image.jpg\"\n}"
|
| 2154 |
-
},
|
| 2155 |
"url": {
|
| 2156 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2157 |
"host": [
|
| 2158 |
"{{base_url}}"
|
| 2159 |
],
|
|
@@ -2161,16 +2569,22 @@
|
|
| 2161 |
"api",
|
| 2162 |
"v1",
|
| 2163 |
"admin",
|
| 2164 |
-
"
|
| 2165 |
-
""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2166 |
]
|
| 2167 |
},
|
| 2168 |
-
"description": "
|
| 2169 |
},
|
| 2170 |
"response": []
|
| 2171 |
},
|
| 2172 |
{
|
| 2173 |
-
"name": "
|
| 2174 |
"request": {
|
| 2175 |
"method": "GET",
|
| 2176 |
"header": [
|
|
@@ -2181,7 +2595,7 @@
|
|
| 2181 |
}
|
| 2182 |
],
|
| 2183 |
"url": {
|
| 2184 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2185 |
"host": [
|
| 2186 |
"{{base_url}}"
|
| 2187 |
],
|
|
@@ -2189,44 +2603,61 @@
|
|
| 2189 |
"api",
|
| 2190 |
"v1",
|
| 2191 |
"admin",
|
| 2192 |
-
"
|
| 2193 |
-
"
|
| 2194 |
-
"
|
| 2195 |
-
"detail"
|
| 2196 |
],
|
| 2197 |
"variable": [
|
| 2198 |
{
|
| 2199 |
-
"key": "
|
| 2200 |
-
"value": ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2201 |
}
|
| 2202 |
]
|
| 2203 |
},
|
| 2204 |
-
"description": "
|
| 2205 |
},
|
| 2206 |
"response": []
|
| 2207 |
},
|
| 2208 |
{
|
| 2209 |
-
"name": "
|
| 2210 |
"request": {
|
| 2211 |
-
"method": "
|
| 2212 |
"header": [
|
| 2213 |
-
{
|
| 2214 |
-
"key": "Content-Type",
|
| 2215 |
-
"value": "application/json",
|
| 2216 |
-
"type": "text"
|
| 2217 |
-
},
|
| 2218 |
{
|
| 2219 |
"key": "Authorization",
|
| 2220 |
"value": "Bearer {{access_token}}",
|
| 2221 |
"type": "text"
|
| 2222 |
}
|
| 2223 |
],
|
| 2224 |
-
"body": {
|
| 2225 |
-
"mode": "raw",
|
| 2226 |
-
"raw": "{\n \"title\": \"Updated Academy Title\",\n \"slug\": \"updated-academy-slug\",\n \"description\": \"Updated description\",\n \"image_url\": \"https://example.com/image.jpg\",\n \"is_public\": true\n}"
|
| 2227 |
-
},
|
| 2228 |
"url": {
|
| 2229 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2230 |
"host": [
|
| 2231 |
"{{base_url}}"
|
| 2232 |
],
|
|
@@ -2234,34 +2665,70 @@
|
|
| 2234 |
"api",
|
| 2235 |
"v1",
|
| 2236 |
"admin",
|
| 2237 |
-
"
|
| 2238 |
-
"
|
| 2239 |
-
"
|
| 2240 |
],
|
| 2241 |
"variable": [
|
| 2242 |
{
|
| 2243 |
-
"key": "
|
| 2244 |
-
"value": ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2245 |
}
|
| 2246 |
]
|
| 2247 |
},
|
| 2248 |
-
"description": "
|
| 2249 |
},
|
| 2250 |
"response": []
|
| 2251 |
},
|
| 2252 |
{
|
| 2253 |
-
"name": "
|
| 2254 |
"request": {
|
| 2255 |
-
"method": "
|
| 2256 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2257 |
{
|
| 2258 |
"key": "Authorization",
|
| 2259 |
"value": "Bearer {{access_token}}",
|
| 2260 |
"type": "text"
|
| 2261 |
}
|
| 2262 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2263 |
"url": {
|
| 2264 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2265 |
"host": [
|
| 2266 |
"{{base_url}}"
|
| 2267 |
],
|
|
@@ -2269,43 +2736,34 @@
|
|
| 2269 |
"api",
|
| 2270 |
"v1",
|
| 2271 |
"admin",
|
| 2272 |
-
"
|
| 2273 |
-
"
|
| 2274 |
-
"
|
| 2275 |
],
|
| 2276 |
"variable": [
|
| 2277 |
{
|
| 2278 |
-
"key": "
|
| 2279 |
-
"value": ""
|
| 2280 |
}
|
| 2281 |
]
|
| 2282 |
},
|
| 2283 |
-
"description": "
|
| 2284 |
},
|
| 2285 |
"response": []
|
| 2286 |
},
|
| 2287 |
{
|
| 2288 |
-
"name": "
|
| 2289 |
"request": {
|
| 2290 |
-
"method": "
|
| 2291 |
"header": [
|
| 2292 |
-
{
|
| 2293 |
-
"key": "Content-Type",
|
| 2294 |
-
"value": "application/json",
|
| 2295 |
-
"type": "text"
|
| 2296 |
-
},
|
| 2297 |
{
|
| 2298 |
"key": "Authorization",
|
| 2299 |
"value": "Bearer {{access_token}}",
|
| 2300 |
"type": "text"
|
| 2301 |
}
|
| 2302 |
],
|
| 2303 |
-
"body": {
|
| 2304 |
-
"mode": "raw",
|
| 2305 |
-
"raw": "{\n \"academy_id\": \"{{academy_id}}\",\n \"title\": \"Material Title\",\n \"slug\": \"material-slug\",\n \"description\": \"Material description\"\n}"
|
| 2306 |
-
},
|
| 2307 |
"url": {
|
| 2308 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2309 |
"host": [
|
| 2310 |
"{{base_url}}"
|
| 2311 |
],
|
|
@@ -2313,18 +2771,30 @@
|
|
| 2313 |
"api",
|
| 2314 |
"v1",
|
| 2315 |
"admin",
|
| 2316 |
-
"
|
| 2317 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2318 |
]
|
| 2319 |
},
|
| 2320 |
-
"description": "
|
| 2321 |
},
|
| 2322 |
"response": []
|
| 2323 |
},
|
| 2324 |
{
|
| 2325 |
-
"name": "
|
| 2326 |
"request": {
|
| 2327 |
-
"method": "
|
| 2328 |
"header": [
|
| 2329 |
{
|
| 2330 |
"key": "Authorization",
|
|
@@ -2333,7 +2803,7 @@
|
|
| 2333 |
}
|
| 2334 |
],
|
| 2335 |
"url": {
|
| 2336 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2337 |
"host": [
|
| 2338 |
"{{base_url}}"
|
| 2339 |
],
|
|
@@ -2341,43 +2811,61 @@
|
|
| 2341 |
"api",
|
| 2342 |
"v1",
|
| 2343 |
"admin",
|
| 2344 |
-
"
|
| 2345 |
-
"
|
| 2346 |
-
"
|
| 2347 |
],
|
| 2348 |
"variable": [
|
| 2349 |
{
|
| 2350 |
-
"key": "
|
| 2351 |
-
"value": ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2352 |
}
|
| 2353 |
]
|
| 2354 |
},
|
| 2355 |
-
"description": "
|
| 2356 |
},
|
| 2357 |
"response": []
|
| 2358 |
},
|
| 2359 |
{
|
| 2360 |
-
"name": "
|
| 2361 |
"request": {
|
| 2362 |
-
"method": "
|
| 2363 |
"header": [
|
| 2364 |
-
{
|
| 2365 |
-
"key": "Content-Type",
|
| 2366 |
-
"value": "application/json",
|
| 2367 |
-
"type": "text"
|
| 2368 |
-
},
|
| 2369 |
{
|
| 2370 |
"key": "Authorization",
|
| 2371 |
"value": "Bearer {{access_token}}",
|
| 2372 |
"type": "text"
|
| 2373 |
}
|
| 2374 |
],
|
| 2375 |
-
"body": {
|
| 2376 |
-
"mode": "raw",
|
| 2377 |
-
"raw": "{\n \"material_id\": \"{{material_id}}\",\n \"title\": \"Content Title\",\n \"contents\": \"Content body text here\"\n}"
|
| 2378 |
-
},
|
| 2379 |
"url": {
|
| 2380 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2381 |
"host": [
|
| 2382 |
"{{base_url}}"
|
| 2383 |
],
|
|
@@ -2385,16 +2873,51 @@
|
|
| 2385 |
"api",
|
| 2386 |
"v1",
|
| 2387 |
"admin",
|
| 2388 |
-
"
|
| 2389 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2390 |
]
|
| 2391 |
},
|
| 2392 |
-
"description": "
|
| 2393 |
},
|
| 2394 |
"response": []
|
| 2395 |
},
|
| 2396 |
{
|
| 2397 |
-
"name": "
|
| 2398 |
"request": {
|
| 2399 |
"method": "DELETE",
|
| 2400 |
"header": [
|
|
@@ -2405,7 +2928,7 @@
|
|
| 2405 |
}
|
| 2406 |
],
|
| 2407 |
"url": {
|
| 2408 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2409 |
"host": [
|
| 2410 |
"{{base_url}}"
|
| 2411 |
],
|
|
@@ -2413,43 +2936,39 @@
|
|
| 2413 |
"api",
|
| 2414 |
"v1",
|
| 2415 |
"admin",
|
| 2416 |
-
"
|
| 2417 |
-
"
|
| 2418 |
-
"
|
|
|
|
| 2419 |
],
|
| 2420 |
"variable": [
|
| 2421 |
{
|
| 2422 |
-
"key": "
|
| 2423 |
-
"value": ""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2424 |
}
|
| 2425 |
]
|
| 2426 |
},
|
| 2427 |
-
"description": "
|
| 2428 |
},
|
| 2429 |
"response": []
|
| 2430 |
},
|
| 2431 |
{
|
| 2432 |
-
"name": "
|
| 2433 |
"request": {
|
| 2434 |
-
"method": "
|
| 2435 |
"header": [
|
| 2436 |
-
{
|
| 2437 |
-
"key": "Content-Type",
|
| 2438 |
-
"value": "application/json",
|
| 2439 |
-
"type": "text"
|
| 2440 |
-
},
|
| 2441 |
{
|
| 2442 |
"key": "Authorization",
|
| 2443 |
"value": "Bearer {{access_token}}",
|
| 2444 |
"type": "text"
|
| 2445 |
}
|
| 2446 |
],
|
| 2447 |
-
"body": {
|
| 2448 |
-
"mode": "raw",
|
| 2449 |
-
"raw": "{\n \"account_id\": \"account_id\",\n \"academy_id\": \"academy_id\"\n}"
|
| 2450 |
-
},
|
| 2451 |
"url": {
|
| 2452 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2453 |
"host": [
|
| 2454 |
"{{base_url}}"
|
| 2455 |
],
|
|
@@ -2457,27 +2976,76 @@
|
|
| 2457 |
"api",
|
| 2458 |
"v1",
|
| 2459 |
"admin",
|
| 2460 |
-
"
|
| 2461 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2462 |
]
|
| 2463 |
},
|
| 2464 |
-
"description": "
|
| 2465 |
},
|
| 2466 |
"response": []
|
| 2467 |
},
|
| 2468 |
{
|
| 2469 |
-
"name": "
|
| 2470 |
"request": {
|
| 2471 |
-
"method": "
|
| 2472 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2473 |
{
|
| 2474 |
"key": "Authorization",
|
| 2475 |
"value": "Bearer {{access_token}}",
|
| 2476 |
"type": "text"
|
| 2477 |
}
|
| 2478 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2479 |
"url": {
|
| 2480 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2481 |
"host": [
|
| 2482 |
"{{base_url}}"
|
| 2483 |
],
|
|
@@ -2485,25 +3053,36 @@
|
|
| 2485 |
"api",
|
| 2486 |
"v1",
|
| 2487 |
"admin",
|
| 2488 |
-
"
|
| 2489 |
-
"
|
| 2490 |
-
"
|
|
|
|
|
|
|
|
|
|
| 2491 |
],
|
| 2492 |
"variable": [
|
| 2493 |
{
|
| 2494 |
-
"key": "
|
| 2495 |
-
"value": ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2496 |
}
|
| 2497 |
]
|
| 2498 |
},
|
| 2499 |
-
"description": "
|
| 2500 |
},
|
| 2501 |
"response": []
|
| 2502 |
},
|
| 2503 |
{
|
| 2504 |
-
"name": "
|
| 2505 |
"request": {
|
| 2506 |
-
"method": "
|
| 2507 |
"header": [
|
| 2508 |
{
|
| 2509 |
"key": "Authorization",
|
|
@@ -2512,7 +3091,7 @@
|
|
| 2512 |
}
|
| 2513 |
],
|
| 2514 |
"url": {
|
| 2515 |
-
"raw": "{{base_url}}/api/v1/admin/
|
| 2516 |
"host": [
|
| 2517 |
"{{base_url}}"
|
| 2518 |
],
|
|
@@ -2520,18 +3099,29 @@
|
|
| 2520 |
"api",
|
| 2521 |
"v1",
|
| 2522 |
"admin",
|
| 2523 |
-
"
|
| 2524 |
-
"
|
| 2525 |
-
"
|
|
|
|
|
|
|
|
|
|
| 2526 |
],
|
| 2527 |
"variable": [
|
| 2528 |
{
|
| 2529 |
-
"key": "
|
| 2530 |
-
"value": ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2531 |
}
|
| 2532 |
]
|
| 2533 |
},
|
| 2534 |
-
"description": "
|
| 2535 |
},
|
| 2536 |
"response": []
|
| 2537 |
}
|
|
@@ -4126,6 +4716,16 @@
|
|
| 4126 |
"key": "material_id",
|
| 4127 |
"value": "",
|
| 4128 |
"type": "string"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4129 |
}
|
| 4130 |
]
|
| 4131 |
-
}
|
|
|
|
| 977 |
"description": "Update progress on academy content"
|
| 978 |
},
|
| 979 |
"response": []
|
| 980 |
+
},
|
| 981 |
+
{
|
| 982 |
+
"name": "Admin",
|
| 983 |
+
"item": [
|
| 984 |
+
{
|
| 985 |
+
"name": "Create Academy",
|
| 986 |
+
"request": {
|
| 987 |
+
"method": "POST",
|
| 988 |
+
"header": [
|
| 989 |
+
{
|
| 990 |
+
"key": "Content-Type",
|
| 991 |
+
"value": "application/json",
|
| 992 |
+
"type": "text"
|
| 993 |
+
},
|
| 994 |
+
{
|
| 995 |
+
"key": "Authorization",
|
| 996 |
+
"value": "Bearer {{access_token}}",
|
| 997 |
+
"type": "text"
|
| 998 |
+
}
|
| 999 |
+
],
|
| 1000 |
+
"body": {
|
| 1001 |
+
"mode": "raw",
|
| 1002 |
+
"raw": "{\n \"title\": \"Academy Title\",\n \"slug\": \"academy-slug\",\n \"code\": \"ACAD01\",\n \"is_public\": true,\n \"description\": \"Academy description\",\n \"image_url\": \"https://example.com/image.jpg\"\n}"
|
| 1003 |
+
},
|
| 1004 |
+
"url": {
|
| 1005 |
+
"raw": "{{base_url}}/api/v1/admin_academy/",
|
| 1006 |
+
"host": [
|
| 1007 |
+
"{{base_url}}"
|
| 1008 |
+
],
|
| 1009 |
+
"path": [
|
| 1010 |
+
"api",
|
| 1011 |
+
"v1",
|
| 1012 |
+
"admin_academy",
|
| 1013 |
+
""
|
| 1014 |
+
]
|
| 1015 |
+
},
|
| 1016 |
+
"description": "Create new academy (admin)"
|
| 1017 |
+
},
|
| 1018 |
+
"response": []
|
| 1019 |
+
},
|
| 1020 |
+
{
|
| 1021 |
+
"name": "Get Academy Detail",
|
| 1022 |
+
"request": {
|
| 1023 |
+
"method": "GET",
|
| 1024 |
+
"header": [
|
| 1025 |
+
{
|
| 1026 |
+
"key": "Authorization",
|
| 1027 |
+
"value": "Bearer {{access_token}}",
|
| 1028 |
+
"type": "text"
|
| 1029 |
+
}
|
| 1030 |
+
],
|
| 1031 |
+
"url": {
|
| 1032 |
+
"raw": "{{base_url}}/api/v1/admin_academy/id/:id/detail",
|
| 1033 |
+
"host": [
|
| 1034 |
+
"{{base_url}}"
|
| 1035 |
+
],
|
| 1036 |
+
"path": [
|
| 1037 |
+
"api",
|
| 1038 |
+
"v1",
|
| 1039 |
+
"admin_academy",
|
| 1040 |
+
"id",
|
| 1041 |
+
":id",
|
| 1042 |
+
"detail"
|
| 1043 |
+
],
|
| 1044 |
+
"variable": [
|
| 1045 |
+
{
|
| 1046 |
+
"key": "id",
|
| 1047 |
+
"value": ""
|
| 1048 |
+
}
|
| 1049 |
+
]
|
| 1050 |
+
},
|
| 1051 |
+
"description": "Get academy detail by ID (admin)"
|
| 1052 |
+
},
|
| 1053 |
+
"response": []
|
| 1054 |
+
},
|
| 1055 |
+
{
|
| 1056 |
+
"name": "Update Academy",
|
| 1057 |
+
"request": {
|
| 1058 |
+
"method": "PUT",
|
| 1059 |
+
"header": [
|
| 1060 |
+
{
|
| 1061 |
+
"key": "Content-Type",
|
| 1062 |
+
"value": "application/json",
|
| 1063 |
+
"type": "text"
|
| 1064 |
+
},
|
| 1065 |
+
{
|
| 1066 |
+
"key": "Authorization",
|
| 1067 |
+
"value": "Bearer {{access_token}}",
|
| 1068 |
+
"type": "text"
|
| 1069 |
+
}
|
| 1070 |
+
],
|
| 1071 |
+
"body": {
|
| 1072 |
+
"mode": "raw",
|
| 1073 |
+
"raw": "{\n \"title\": \"Updated Academy Title\",\n \"slug\": \"updated-academy-slug\",\n \"description\": \"Updated description\",\n \"image_url\": \"https://example.com/image.jpg\",\n \"is_public\": true\n}"
|
| 1074 |
+
},
|
| 1075 |
+
"url": {
|
| 1076 |
+
"raw": "{{base_url}}/api/v1/admin_academy/id/:id",
|
| 1077 |
+
"host": [
|
| 1078 |
+
"{{base_url}}"
|
| 1079 |
+
],
|
| 1080 |
+
"path": [
|
| 1081 |
+
"api",
|
| 1082 |
+
"v1",
|
| 1083 |
+
"admin_academy",
|
| 1084 |
+
"id",
|
| 1085 |
+
":id"
|
| 1086 |
+
],
|
| 1087 |
+
"variable": [
|
| 1088 |
+
{
|
| 1089 |
+
"key": "id",
|
| 1090 |
+
"value": ""
|
| 1091 |
+
}
|
| 1092 |
+
]
|
| 1093 |
+
},
|
| 1094 |
+
"description": "Update academy (admin)"
|
| 1095 |
+
},
|
| 1096 |
+
"response": []
|
| 1097 |
+
},
|
| 1098 |
+
{
|
| 1099 |
+
"name": "Delete Academy",
|
| 1100 |
+
"request": {
|
| 1101 |
+
"method": "DELETE",
|
| 1102 |
+
"header": [
|
| 1103 |
+
{
|
| 1104 |
+
"key": "Authorization",
|
| 1105 |
+
"value": "Bearer {{access_token}}",
|
| 1106 |
+
"type": "text"
|
| 1107 |
+
}
|
| 1108 |
+
],
|
| 1109 |
+
"url": {
|
| 1110 |
+
"raw": "{{base_url}}/api/v1/admin_academy/id/:id",
|
| 1111 |
+
"host": [
|
| 1112 |
+
"{{base_url}}"
|
| 1113 |
+
],
|
| 1114 |
+
"path": [
|
| 1115 |
+
"api",
|
| 1116 |
+
"v1",
|
| 1117 |
+
"admin_academy",
|
| 1118 |
+
"id",
|
| 1119 |
+
":id"
|
| 1120 |
+
],
|
| 1121 |
+
"variable": [
|
| 1122 |
+
{
|
| 1123 |
+
"key": "id",
|
| 1124 |
+
"value": ""
|
| 1125 |
+
}
|
| 1126 |
+
]
|
| 1127 |
+
},
|
| 1128 |
+
"description": "Delete academy (admin)"
|
| 1129 |
+
},
|
| 1130 |
+
"response": []
|
| 1131 |
+
},
|
| 1132 |
+
{
|
| 1133 |
+
"name": "Create Material",
|
| 1134 |
+
"request": {
|
| 1135 |
+
"method": "POST",
|
| 1136 |
+
"header": [
|
| 1137 |
+
{
|
| 1138 |
+
"key": "Content-Type",
|
| 1139 |
+
"value": "application/json",
|
| 1140 |
+
"type": "text"
|
| 1141 |
+
},
|
| 1142 |
+
{
|
| 1143 |
+
"key": "Authorization",
|
| 1144 |
+
"value": "Bearer {{access_token}}",
|
| 1145 |
+
"type": "text"
|
| 1146 |
+
}
|
| 1147 |
+
],
|
| 1148 |
+
"body": {
|
| 1149 |
+
"mode": "raw",
|
| 1150 |
+
"raw": "{\n \"academy_id\": \"{{academy_id}}\",\n \"title\": \"Material Title\",\n \"slug\": \"material-slug\",\n \"description\": \"Material description\"\n}"
|
| 1151 |
+
},
|
| 1152 |
+
"url": {
|
| 1153 |
+
"raw": "{{base_url}}/api/v1/admin_academy/materials",
|
| 1154 |
+
"host": [
|
| 1155 |
+
"{{base_url}}"
|
| 1156 |
+
],
|
| 1157 |
+
"path": [
|
| 1158 |
+
"api",
|
| 1159 |
+
"v1",
|
| 1160 |
+
"admin_academy",
|
| 1161 |
+
"materials"
|
| 1162 |
+
]
|
| 1163 |
+
},
|
| 1164 |
+
"description": "Create academy material (admin)"
|
| 1165 |
+
},
|
| 1166 |
+
"response": []
|
| 1167 |
+
},
|
| 1168 |
+
{
|
| 1169 |
+
"name": "Delete Material",
|
| 1170 |
+
"request": {
|
| 1171 |
+
"method": "DELETE",
|
| 1172 |
+
"header": [
|
| 1173 |
+
{
|
| 1174 |
+
"key": "Authorization",
|
| 1175 |
+
"value": "Bearer {{access_token}}",
|
| 1176 |
+
"type": "text"
|
| 1177 |
+
}
|
| 1178 |
+
],
|
| 1179 |
+
"url": {
|
| 1180 |
+
"raw": "{{base_url}}/api/v1/admin_academy/materials/:id",
|
| 1181 |
+
"host": [
|
| 1182 |
+
"{{base_url}}"
|
| 1183 |
+
],
|
| 1184 |
+
"path": [
|
| 1185 |
+
"api",
|
| 1186 |
+
"v1",
|
| 1187 |
+
"admin_academy",
|
| 1188 |
+
"materials",
|
| 1189 |
+
":id"
|
| 1190 |
+
],
|
| 1191 |
+
"variable": [
|
| 1192 |
+
{
|
| 1193 |
+
"key": "id",
|
| 1194 |
+
"value": ""
|
| 1195 |
+
}
|
| 1196 |
+
]
|
| 1197 |
+
},
|
| 1198 |
+
"description": "Delete academy material (admin)"
|
| 1199 |
+
},
|
| 1200 |
+
"response": []
|
| 1201 |
+
},
|
| 1202 |
+
{
|
| 1203 |
+
"name": "Create Content",
|
| 1204 |
+
"request": {
|
| 1205 |
+
"method": "POST",
|
| 1206 |
+
"header": [
|
| 1207 |
+
{
|
| 1208 |
+
"key": "Content-Type",
|
| 1209 |
+
"value": "application/json",
|
| 1210 |
+
"type": "text"
|
| 1211 |
+
},
|
| 1212 |
+
{
|
| 1213 |
+
"key": "Authorization",
|
| 1214 |
+
"value": "Bearer {{access_token}}",
|
| 1215 |
+
"type": "text"
|
| 1216 |
+
}
|
| 1217 |
+
],
|
| 1218 |
+
"body": {
|
| 1219 |
+
"mode": "raw",
|
| 1220 |
+
"raw": "{\n \"material_id\": \"{{material_id}}\",\n \"title\": \"Content Title\",\n \"contents\": \"Content body text here\"\n}"
|
| 1221 |
+
},
|
| 1222 |
+
"url": {
|
| 1223 |
+
"raw": "{{base_url}}/api/v1/admin_academy/contents",
|
| 1224 |
+
"host": [
|
| 1225 |
+
"{{base_url}}"
|
| 1226 |
+
],
|
| 1227 |
+
"path": [
|
| 1228 |
+
"api",
|
| 1229 |
+
"v1",
|
| 1230 |
+
"admin_academy",
|
| 1231 |
+
"contents"
|
| 1232 |
+
]
|
| 1233 |
+
},
|
| 1234 |
+
"description": "Create academy content (admin)"
|
| 1235 |
+
},
|
| 1236 |
+
"response": []
|
| 1237 |
+
},
|
| 1238 |
+
{
|
| 1239 |
+
"name": "Delete Content",
|
| 1240 |
+
"request": {
|
| 1241 |
+
"method": "DELETE",
|
| 1242 |
+
"header": [
|
| 1243 |
+
{
|
| 1244 |
+
"key": "Authorization",
|
| 1245 |
+
"value": "Bearer {{access_token}}",
|
| 1246 |
+
"type": "text"
|
| 1247 |
+
}
|
| 1248 |
+
],
|
| 1249 |
+
"url": {
|
| 1250 |
+
"raw": "{{base_url}}/api/v1/admin_academy/contents/:id",
|
| 1251 |
+
"host": [
|
| 1252 |
+
"{{base_url}}"
|
| 1253 |
+
],
|
| 1254 |
+
"path": [
|
| 1255 |
+
"api",
|
| 1256 |
+
"v1",
|
| 1257 |
+
"admin_academy",
|
| 1258 |
+
"contents",
|
| 1259 |
+
":id"
|
| 1260 |
+
],
|
| 1261 |
+
"variable": [
|
| 1262 |
+
{
|
| 1263 |
+
"key": "id",
|
| 1264 |
+
"value": ""
|
| 1265 |
+
}
|
| 1266 |
+
]
|
| 1267 |
+
},
|
| 1268 |
+
"description": "Delete academy content (admin)"
|
| 1269 |
+
},
|
| 1270 |
+
"response": []
|
| 1271 |
+
},
|
| 1272 |
+
{
|
| 1273 |
+
"name": "Assign Account to Academy",
|
| 1274 |
+
"request": {
|
| 1275 |
+
"method": "POST",
|
| 1276 |
+
"header": [
|
| 1277 |
+
{
|
| 1278 |
+
"key": "Content-Type",
|
| 1279 |
+
"value": "application/json",
|
| 1280 |
+
"type": "text"
|
| 1281 |
+
},
|
| 1282 |
+
{
|
| 1283 |
+
"key": "Authorization",
|
| 1284 |
+
"value": "Bearer {{access_token}}",
|
| 1285 |
+
"type": "text"
|
| 1286 |
+
}
|
| 1287 |
+
],
|
| 1288 |
+
"body": {
|
| 1289 |
+
"mode": "raw",
|
| 1290 |
+
"raw": "{\n \"account_id\": \"account_id\",\n \"academy_id\": \"academy_id\"\n}"
|
| 1291 |
+
},
|
| 1292 |
+
"url": {
|
| 1293 |
+
"raw": "{{base_url}}/api/v1/admin_academy/assign",
|
| 1294 |
+
"host": [
|
| 1295 |
+
"{{base_url}}"
|
| 1296 |
+
],
|
| 1297 |
+
"path": [
|
| 1298 |
+
"api",
|
| 1299 |
+
"v1",
|
| 1300 |
+
"admin_academy",
|
| 1301 |
+
"assign"
|
| 1302 |
+
]
|
| 1303 |
+
},
|
| 1304 |
+
"description": "Assign user account to academy (admin)"
|
| 1305 |
+
},
|
| 1306 |
+
"response": []
|
| 1307 |
+
},
|
| 1308 |
+
{
|
| 1309 |
+
"name": "Unassign Account from Academy",
|
| 1310 |
+
"request": {
|
| 1311 |
+
"method": "DELETE",
|
| 1312 |
+
"header": [
|
| 1313 |
+
{
|
| 1314 |
+
"key": "Authorization",
|
| 1315 |
+
"value": "Bearer {{access_token}}",
|
| 1316 |
+
"type": "text"
|
| 1317 |
+
}
|
| 1318 |
+
],
|
| 1319 |
+
"url": {
|
| 1320 |
+
"raw": "{{base_url}}/api/v1/admin_academy/assign/:id",
|
| 1321 |
+
"host": [
|
| 1322 |
+
"{{base_url}}"
|
| 1323 |
+
],
|
| 1324 |
+
"path": [
|
| 1325 |
+
"api",
|
| 1326 |
+
"v1",
|
| 1327 |
+
"admin_academy",
|
| 1328 |
+
"assign",
|
| 1329 |
+
":id"
|
| 1330 |
+
],
|
| 1331 |
+
"variable": [
|
| 1332 |
+
{
|
| 1333 |
+
"key": "id",
|
| 1334 |
+
"value": ""
|
| 1335 |
+
}
|
| 1336 |
+
]
|
| 1337 |
+
},
|
| 1338 |
+
"description": "Unassign user account from academy (admin)"
|
| 1339 |
+
},
|
| 1340 |
+
"response": []
|
| 1341 |
+
},
|
| 1342 |
+
{
|
| 1343 |
+
"name": "List Academy Assignments",
|
| 1344 |
+
"request": {
|
| 1345 |
+
"method": "GET",
|
| 1346 |
+
"header": [
|
| 1347 |
+
{
|
| 1348 |
+
"key": "Authorization",
|
| 1349 |
+
"value": "Bearer {{access_token}}",
|
| 1350 |
+
"type": "text"
|
| 1351 |
+
}
|
| 1352 |
+
],
|
| 1353 |
+
"url": {
|
| 1354 |
+
"raw": "{{base_url}}/api/v1/admin_academy/assign/:academy_id",
|
| 1355 |
+
"host": [
|
| 1356 |
+
"{{base_url}}"
|
| 1357 |
+
],
|
| 1358 |
+
"path": [
|
| 1359 |
+
"api",
|
| 1360 |
+
"v1",
|
| 1361 |
+
"admin_academy",
|
| 1362 |
+
"assign",
|
| 1363 |
+
":academy_id"
|
| 1364 |
+
],
|
| 1365 |
+
"variable": [
|
| 1366 |
+
{
|
| 1367 |
+
"key": "academy_id",
|
| 1368 |
+
"value": ""
|
| 1369 |
+
}
|
| 1370 |
+
]
|
| 1371 |
+
},
|
| 1372 |
+
"description": "List academy assignments by academy ID (admin)"
|
| 1373 |
+
},
|
| 1374 |
+
"response": []
|
| 1375 |
+
},
|
| 1376 |
+
{
|
| 1377 |
+
"name": "Admin - List Materials by Academy",
|
| 1378 |
+
"request": {
|
| 1379 |
+
"method": "GET",
|
| 1380 |
+
"header": [
|
| 1381 |
+
{
|
| 1382 |
+
"key": "Authorization",
|
| 1383 |
+
"value": "Bearer {{access_token}}",
|
| 1384 |
+
"type": "text"
|
| 1385 |
+
}
|
| 1386 |
+
],
|
| 1387 |
+
"url": {
|
| 1388 |
+
"raw": "{{base_url}}/api/v1/admin_academy/id/:id/materials",
|
| 1389 |
+
"host": [
|
| 1390 |
+
"{{base_url}}"
|
| 1391 |
+
],
|
| 1392 |
+
"path": [
|
| 1393 |
+
"api",
|
| 1394 |
+
"v1",
|
| 1395 |
+
"admin_academy",
|
| 1396 |
+
"id",
|
| 1397 |
+
":id",
|
| 1398 |
+
"materials"
|
| 1399 |
+
],
|
| 1400 |
+
"variable": [
|
| 1401 |
+
{
|
| 1402 |
+
"key": "id",
|
| 1403 |
+
"value": "{{academy_id}}"
|
| 1404 |
+
}
|
| 1405 |
+
]
|
| 1406 |
+
},
|
| 1407 |
+
"description": "List materials for a specific academy (Admin)"
|
| 1408 |
+
},
|
| 1409 |
+
"response": []
|
| 1410 |
+
},
|
| 1411 |
+
{
|
| 1412 |
+
"name": "Admin - Get Material Detail",
|
| 1413 |
+
"request": {
|
| 1414 |
+
"method": "GET",
|
| 1415 |
+
"header": [
|
| 1416 |
+
{
|
| 1417 |
+
"key": "Authorization",
|
| 1418 |
+
"value": "Bearer {{access_token}}",
|
| 1419 |
+
"type": "text"
|
| 1420 |
+
}
|
| 1421 |
+
],
|
| 1422 |
+
"url": {
|
| 1423 |
+
"raw": "{{base_url}}/api/v1/admin_academy/materials/id/:id/detail",
|
| 1424 |
+
"host": [
|
| 1425 |
+
"{{base_url}}"
|
| 1426 |
+
],
|
| 1427 |
+
"path": [
|
| 1428 |
+
"api",
|
| 1429 |
+
"v1",
|
| 1430 |
+
"admin_academy",
|
| 1431 |
+
"materials",
|
| 1432 |
+
"id",
|
| 1433 |
+
":id",
|
| 1434 |
+
"detail"
|
| 1435 |
+
],
|
| 1436 |
+
"variable": [
|
| 1437 |
+
{
|
| 1438 |
+
"key": "id",
|
| 1439 |
+
"value": "{{material_id}}"
|
| 1440 |
+
}
|
| 1441 |
+
]
|
| 1442 |
+
},
|
| 1443 |
+
"description": "Get detailed material information (Admin)"
|
| 1444 |
+
},
|
| 1445 |
+
"response": []
|
| 1446 |
+
},
|
| 1447 |
+
{
|
| 1448 |
+
"name": "Admin - Update Material",
|
| 1449 |
+
"request": {
|
| 1450 |
+
"method": "PUT",
|
| 1451 |
+
"header": [
|
| 1452 |
+
{
|
| 1453 |
+
"key": "Content-Type",
|
| 1454 |
+
"value": "application/json",
|
| 1455 |
+
"type": "text"
|
| 1456 |
+
},
|
| 1457 |
+
{
|
| 1458 |
+
"key": "Authorization",
|
| 1459 |
+
"value": "Bearer {{access_token}}",
|
| 1460 |
+
"type": "text"
|
| 1461 |
+
}
|
| 1462 |
+
],
|
| 1463 |
+
"body": {
|
| 1464 |
+
"mode": "raw",
|
| 1465 |
+
"raw": "{\n \"title\": \"Updated Material Title\",\n \"slug\": \"updated-material-slug\",\n \"description\": \"Updated description\"\n}"
|
| 1466 |
+
},
|
| 1467 |
+
"url": {
|
| 1468 |
+
"raw": "{{base_url}}/api/v1/admin_academy/materials/id/:id",
|
| 1469 |
+
"host": [
|
| 1470 |
+
"{{base_url}}"
|
| 1471 |
+
],
|
| 1472 |
+
"path": [
|
| 1473 |
+
"api",
|
| 1474 |
+
"v1",
|
| 1475 |
+
"admin_academy",
|
| 1476 |
+
"materials",
|
| 1477 |
+
"id",
|
| 1478 |
+
":id"
|
| 1479 |
+
],
|
| 1480 |
+
"variable": [
|
| 1481 |
+
{
|
| 1482 |
+
"key": "id",
|
| 1483 |
+
"value": "{{material_id}}"
|
| 1484 |
+
}
|
| 1485 |
+
]
|
| 1486 |
+
},
|
| 1487 |
+
"description": "Update an existing material (Admin)"
|
| 1488 |
+
},
|
| 1489 |
+
"response": []
|
| 1490 |
+
},
|
| 1491 |
+
{
|
| 1492 |
+
"name": "Admin - List Contents by Material",
|
| 1493 |
+
"request": {
|
| 1494 |
+
"method": "GET",
|
| 1495 |
+
"header": [
|
| 1496 |
+
{
|
| 1497 |
+
"key": "Authorization",
|
| 1498 |
+
"value": "Bearer {{access_token}}",
|
| 1499 |
+
"type": "text"
|
| 1500 |
+
}
|
| 1501 |
+
],
|
| 1502 |
+
"url": {
|
| 1503 |
+
"raw": "{{base_url}}/api/v1/admin_academy/materials/id/:id/contents",
|
| 1504 |
+
"host": [
|
| 1505 |
+
"{{base_url}}"
|
| 1506 |
+
],
|
| 1507 |
+
"path": [
|
| 1508 |
+
"api",
|
| 1509 |
+
"v1",
|
| 1510 |
+
"admin_academy",
|
| 1511 |
+
"materials",
|
| 1512 |
+
"id",
|
| 1513 |
+
":id",
|
| 1514 |
+
"contents"
|
| 1515 |
+
],
|
| 1516 |
+
"variable": [
|
| 1517 |
+
{
|
| 1518 |
+
"key": "id",
|
| 1519 |
+
"value": "{{material_id}}"
|
| 1520 |
+
}
|
| 1521 |
+
]
|
| 1522 |
+
},
|
| 1523 |
+
"description": "List contents for a specific material (Admin)"
|
| 1524 |
+
},
|
| 1525 |
+
"response": []
|
| 1526 |
+
},
|
| 1527 |
+
{
|
| 1528 |
+
"name": "Admin - Get Content Detail",
|
| 1529 |
+
"request": {
|
| 1530 |
+
"method": "GET",
|
| 1531 |
+
"header": [
|
| 1532 |
+
{
|
| 1533 |
+
"key": "Authorization",
|
| 1534 |
+
"value": "Bearer {{access_token}}",
|
| 1535 |
+
"type": "text"
|
| 1536 |
+
}
|
| 1537 |
+
],
|
| 1538 |
+
"url": {
|
| 1539 |
+
"raw": "{{base_url}}/api/v1/admin_academy/contents/id/:id/detail",
|
| 1540 |
+
"host": [
|
| 1541 |
+
"{{base_url}}"
|
| 1542 |
+
],
|
| 1543 |
+
"path": [
|
| 1544 |
+
"api",
|
| 1545 |
+
"v1",
|
| 1546 |
+
"admin_academy",
|
| 1547 |
+
"contents",
|
| 1548 |
+
"id",
|
| 1549 |
+
":id",
|
| 1550 |
+
"detail"
|
| 1551 |
+
],
|
| 1552 |
+
"variable": [
|
| 1553 |
+
{
|
| 1554 |
+
"key": "id",
|
| 1555 |
+
"value": "{{content_id}}"
|
| 1556 |
+
}
|
| 1557 |
+
]
|
| 1558 |
+
},
|
| 1559 |
+
"description": "Get detailed content information (Admin)"
|
| 1560 |
+
},
|
| 1561 |
+
"response": []
|
| 1562 |
+
},
|
| 1563 |
+
{
|
| 1564 |
+
"name": "Admin - Update Content",
|
| 1565 |
+
"request": {
|
| 1566 |
+
"method": "PUT",
|
| 1567 |
+
"header": [
|
| 1568 |
+
{
|
| 1569 |
+
"key": "Content-Type",
|
| 1570 |
+
"value": "application/json",
|
| 1571 |
+
"type": "text"
|
| 1572 |
+
},
|
| 1573 |
+
{
|
| 1574 |
+
"key": "Authorization",
|
| 1575 |
+
"value": "Bearer {{access_token}}",
|
| 1576 |
+
"type": "text"
|
| 1577 |
+
}
|
| 1578 |
+
],
|
| 1579 |
+
"body": {
|
| 1580 |
+
"mode": "raw",
|
| 1581 |
+
"raw": "{\n \"title\": \"Updated Content Title\",\n \"contents\": \"<p>Updated content body</p>\"\n}"
|
| 1582 |
+
},
|
| 1583 |
+
"url": {
|
| 1584 |
+
"raw": "{{base_url}}/api/v1/admin_academy/contents/id/:id",
|
| 1585 |
+
"host": [
|
| 1586 |
+
"{{base_url}}"
|
| 1587 |
+
],
|
| 1588 |
+
"path": [
|
| 1589 |
+
"api",
|
| 1590 |
+
"v1",
|
| 1591 |
+
"admin_academy",
|
| 1592 |
+
"contents",
|
| 1593 |
+
"id",
|
| 1594 |
+
":id"
|
| 1595 |
+
],
|
| 1596 |
+
"variable": [
|
| 1597 |
+
{
|
| 1598 |
+
"key": "id",
|
| 1599 |
+
"value": "{{content_id}}"
|
| 1600 |
+
}
|
| 1601 |
+
]
|
| 1602 |
+
},
|
| 1603 |
+
"description": "Update an existing content (Admin)"
|
| 1604 |
+
},
|
| 1605 |
+
"response": []
|
| 1606 |
+
}
|
| 1607 |
+
]
|
| 1608 |
}
|
| 1609 |
]
|
| 1610 |
},
|
|
|
|
| 2042 |
"name": "Admin",
|
| 2043 |
"item": [
|
| 2044 |
{
|
| 2045 |
+
"name": "Admin Statistics",
|
| 2046 |
"item": [
|
| 2047 |
{
|
| 2048 |
+
"name": "Get Statistics Summary",
|
| 2049 |
"request": {
|
| 2050 |
"method": "GET",
|
| 2051 |
"header": [
|
|
|
|
| 2056 |
}
|
| 2057 |
],
|
| 2058 |
"url": {
|
| 2059 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/summary",
|
| 2060 |
"host": [
|
| 2061 |
"{{base_url}}"
|
| 2062 |
],
|
|
|
|
| 2064 |
"api",
|
| 2065 |
"v1",
|
| 2066 |
"admin",
|
| 2067 |
+
"statistics",
|
| 2068 |
+
"summary"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2069 |
]
|
| 2070 |
+
}
|
|
|
|
| 2071 |
},
|
| 2072 |
"response": []
|
| 2073 |
},
|
| 2074 |
{
|
| 2075 |
+
"name": "Get Monthly Growth Statistics",
|
| 2076 |
"request": {
|
| 2077 |
+
"method": "GET",
|
| 2078 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2079 |
{
|
| 2080 |
"key": "Authorization",
|
| 2081 |
"value": "Bearer {{access_token}}",
|
| 2082 |
"type": "text"
|
| 2083 |
}
|
| 2084 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2085 |
"url": {
|
| 2086 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/monthly-growth?months=6",
|
| 2087 |
"host": [
|
| 2088 |
"{{base_url}}"
|
| 2089 |
],
|
|
|
|
| 2091 |
"api",
|
| 2092 |
"v1",
|
| 2093 |
"admin",
|
| 2094 |
+
"statistics",
|
| 2095 |
+
"monthly-growth"
|
| 2096 |
+
],
|
| 2097 |
+
"query": [
|
| 2098 |
+
{
|
| 2099 |
+
"key": "months",
|
| 2100 |
+
"value": "6"
|
| 2101 |
+
}
|
| 2102 |
]
|
| 2103 |
+
}
|
|
|
|
| 2104 |
},
|
| 2105 |
"response": []
|
| 2106 |
},
|
| 2107 |
{
|
| 2108 |
+
"name": "Event Statistics Overview",
|
| 2109 |
"request": {
|
| 2110 |
+
"method": "GET",
|
| 2111 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2112 |
{
|
| 2113 |
"key": "Authorization",
|
| 2114 |
"value": "Bearer {{access_token}}",
|
| 2115 |
"type": "text"
|
| 2116 |
}
|
| 2117 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2118 |
"url": {
|
| 2119 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/event",
|
| 2120 |
"host": [
|
| 2121 |
"{{base_url}}"
|
| 2122 |
],
|
|
|
|
| 2124 |
"api",
|
| 2125 |
"v1",
|
| 2126 |
"admin",
|
| 2127 |
+
"statistics",
|
| 2128 |
+
"event"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2129 |
]
|
| 2130 |
+
}
|
|
|
|
| 2131 |
},
|
| 2132 |
"response": []
|
| 2133 |
},
|
| 2134 |
{
|
| 2135 |
+
"name": "Event Statistics Detail",
|
| 2136 |
"request": {
|
| 2137 |
+
"method": "GET",
|
| 2138 |
"header": [
|
| 2139 |
{
|
| 2140 |
"key": "Authorization",
|
|
|
|
| 2143 |
}
|
| 2144 |
],
|
| 2145 |
"url": {
|
| 2146 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/event/:event_id",
|
| 2147 |
"host": [
|
| 2148 |
"{{base_url}}"
|
| 2149 |
],
|
|
|
|
| 2151 |
"api",
|
| 2152 |
"v1",
|
| 2153 |
"admin",
|
| 2154 |
+
"statistics",
|
| 2155 |
+
"event",
|
| 2156 |
":event_id"
|
| 2157 |
],
|
| 2158 |
"variable": [
|
|
|
|
| 2161 |
"value": "{{event_id}}"
|
| 2162 |
}
|
| 2163 |
]
|
| 2164 |
+
}
|
|
|
|
| 2165 |
},
|
| 2166 |
"response": []
|
| 2167 |
},
|
| 2168 |
{
|
| 2169 |
+
"name": "Exam Statistics Overview",
|
| 2170 |
"request": {
|
| 2171 |
"method": "GET",
|
| 2172 |
"header": [
|
|
|
|
| 2174 |
"key": "Authorization",
|
| 2175 |
"value": "Bearer {{access_token}}",
|
| 2176 |
"type": "text"
|
| 2177 |
+
}
|
| 2178 |
+
],
|
| 2179 |
+
"url": {
|
| 2180 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/exam",
|
| 2181 |
+
"host": [
|
| 2182 |
+
"{{base_url}}"
|
| 2183 |
+
],
|
| 2184 |
+
"path": [
|
| 2185 |
+
"api",
|
| 2186 |
+
"v1",
|
| 2187 |
+
"admin",
|
| 2188 |
+
"statistics",
|
| 2189 |
+
"exam"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2190 |
]
|
| 2191 |
+
}
|
|
|
|
| 2192 |
},
|
| 2193 |
"response": []
|
| 2194 |
},
|
| 2195 |
{
|
| 2196 |
+
"name": "Exam Statistics Detail",
|
| 2197 |
"request": {
|
| 2198 |
"method": "GET",
|
| 2199 |
"header": [
|
|
|
|
| 2204 |
}
|
| 2205 |
],
|
| 2206 |
"url": {
|
| 2207 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/exam/:exam_id",
|
| 2208 |
"host": [
|
| 2209 |
"{{base_url}}"
|
| 2210 |
],
|
|
|
|
| 2212 |
"api",
|
| 2213 |
"v1",
|
| 2214 |
"admin",
|
| 2215 |
+
"statistics",
|
| 2216 |
+
"exam",
|
| 2217 |
+
":exam_id"
|
| 2218 |
],
|
| 2219 |
"variable": [
|
| 2220 |
{
|
| 2221 |
+
"key": "exam_id",
|
| 2222 |
+
"value": "{{exam_id}}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2223 |
}
|
| 2224 |
]
|
| 2225 |
+
}
|
|
|
|
| 2226 |
},
|
| 2227 |
"response": []
|
| 2228 |
},
|
| 2229 |
{
|
| 2230 |
+
"name": "Academy Statistics Overview",
|
| 2231 |
"request": {
|
| 2232 |
+
"method": "GET",
|
| 2233 |
"header": [
|
| 2234 |
{
|
| 2235 |
+
"key": "Authorization",
|
| 2236 |
+
"value": "Bearer {{access_token}}",
|
| 2237 |
"type": "text"
|
| 2238 |
+
}
|
| 2239 |
+
],
|
| 2240 |
+
"url": {
|
| 2241 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/academy",
|
| 2242 |
+
"host": [
|
| 2243 |
+
"{{base_url}}"
|
| 2244 |
+
],
|
| 2245 |
+
"path": [
|
| 2246 |
+
"api",
|
| 2247 |
+
"v1",
|
| 2248 |
+
"admin",
|
| 2249 |
+
"statistics",
|
| 2250 |
+
"academy"
|
| 2251 |
+
]
|
| 2252 |
+
}
|
| 2253 |
+
},
|
| 2254 |
+
"response": []
|
| 2255 |
+
},
|
| 2256 |
+
{
|
| 2257 |
+
"name": "Academy Statistics Detail",
|
| 2258 |
+
"request": {
|
| 2259 |
+
"method": "GET",
|
| 2260 |
+
"header": [
|
| 2261 |
{
|
| 2262 |
"key": "Authorization",
|
| 2263 |
"value": "Bearer {{access_token}}",
|
| 2264 |
"type": "text"
|
| 2265 |
}
|
| 2266 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2267 |
"url": {
|
| 2268 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/academy/:academy_id",
|
| 2269 |
"host": [
|
| 2270 |
"{{base_url}}"
|
| 2271 |
],
|
|
|
|
| 2273 |
"api",
|
| 2274 |
"v1",
|
| 2275 |
"admin",
|
| 2276 |
+
"statistics",
|
| 2277 |
+
"academy",
|
| 2278 |
+
":academy_id"
|
| 2279 |
],
|
| 2280 |
"variable": [
|
| 2281 |
{
|
| 2282 |
+
"key": "academy_id",
|
| 2283 |
+
"value": "{{academy_id}}"
|
| 2284 |
}
|
| 2285 |
]
|
| 2286 |
+
}
|
|
|
|
| 2287 |
},
|
| 2288 |
"response": []
|
| 2289 |
},
|
| 2290 |
{
|
| 2291 |
+
"name": "ProblemSet Statistics Overview",
|
| 2292 |
"request": {
|
| 2293 |
+
"method": "GET",
|
| 2294 |
"header": [
|
| 2295 |
{
|
| 2296 |
"key": "Authorization",
|
|
|
|
| 2299 |
}
|
| 2300 |
],
|
| 2301 |
"url": {
|
| 2302 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/problemset",
|
| 2303 |
"host": [
|
| 2304 |
"{{base_url}}"
|
| 2305 |
],
|
|
|
|
| 2307 |
"api",
|
| 2308 |
"v1",
|
| 2309 |
"admin",
|
| 2310 |
+
"statistics",
|
| 2311 |
+
"problemset"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2312 |
]
|
| 2313 |
+
}
|
|
|
|
| 2314 |
},
|
| 2315 |
"response": []
|
| 2316 |
},
|
| 2317 |
{
|
| 2318 |
+
"name": "ProblemSet Statistics Detail",
|
| 2319 |
"request": {
|
| 2320 |
"method": "GET",
|
| 2321 |
"header": [
|
|
|
|
| 2326 |
}
|
| 2327 |
],
|
| 2328 |
"url": {
|
| 2329 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/problemset/:problemset_id",
|
| 2330 |
"host": [
|
| 2331 |
"{{base_url}}"
|
| 2332 |
],
|
|
|
|
| 2334 |
"api",
|
| 2335 |
"v1",
|
| 2336 |
"admin",
|
| 2337 |
+
"statistics",
|
| 2338 |
+
"problemset",
|
| 2339 |
+
":problemset_id"
|
| 2340 |
],
|
| 2341 |
"variable": [
|
| 2342 |
{
|
| 2343 |
+
"key": "problemset_id",
|
| 2344 |
+
"value": "{{problemset_id}}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2345 |
}
|
| 2346 |
]
|
| 2347 |
+
}
|
|
|
|
| 2348 |
},
|
| 2349 |
"response": []
|
| 2350 |
},
|
| 2351 |
{
|
| 2352 |
+
"name": "Question Statistics Overview",
|
| 2353 |
"request": {
|
| 2354 |
"method": "GET",
|
| 2355 |
"header": [
|
|
|
|
| 2360 |
}
|
| 2361 |
],
|
| 2362 |
"url": {
|
| 2363 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/question",
|
| 2364 |
"host": [
|
| 2365 |
"{{base_url}}"
|
| 2366 |
],
|
|
|
|
| 2368 |
"api",
|
| 2369 |
"v1",
|
| 2370 |
"admin",
|
| 2371 |
+
"statistics",
|
| 2372 |
+
"question"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2373 |
]
|
| 2374 |
+
}
|
|
|
|
| 2375 |
},
|
| 2376 |
"response": []
|
| 2377 |
},
|
| 2378 |
{
|
| 2379 |
+
"name": "Question Statistics Detail",
|
| 2380 |
"request": {
|
| 2381 |
+
"method": "GET",
|
| 2382 |
"header": [
|
| 2383 |
{
|
| 2384 |
"key": "Authorization",
|
|
|
|
| 2387 |
}
|
| 2388 |
],
|
| 2389 |
"url": {
|
| 2390 |
+
"raw": "{{base_url}}/api/v1/admin/statistics/question/:question_id",
|
| 2391 |
"host": [
|
| 2392 |
"{{base_url}}"
|
| 2393 |
],
|
|
|
|
| 2395 |
"api",
|
| 2396 |
"v1",
|
| 2397 |
"admin",
|
| 2398 |
+
"statistics",
|
| 2399 |
+
"question",
|
| 2400 |
+
":question_id"
|
|
|
|
| 2401 |
],
|
| 2402 |
"variable": [
|
| 2403 |
{
|
| 2404 |
+
"key": "question_id",
|
| 2405 |
+
"value": "{{question_id}}"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2406 |
}
|
| 2407 |
]
|
| 2408 |
+
}
|
|
|
|
| 2409 |
},
|
| 2410 |
"response": []
|
| 2411 |
+
}
|
| 2412 |
+
]
|
| 2413 |
+
},
|
| 2414 |
+
{
|
| 2415 |
+
"name": "Admin Event Management",
|
| 2416 |
+
"item": [
|
| 2417 |
{
|
| 2418 |
+
"name": "List Events (Admin View)",
|
| 2419 |
"request": {
|
| 2420 |
"method": "GET",
|
| 2421 |
"header": [
|
|
|
|
| 2426 |
}
|
| 2427 |
],
|
| 2428 |
"url": {
|
| 2429 |
+
"raw": "{{base_url}}/api/v1/admin/events/?page=1&limit=10&search=&sortBy=created_at&order=desc",
|
| 2430 |
"host": [
|
| 2431 |
"{{base_url}}"
|
| 2432 |
],
|
|
|
|
| 2435 |
"v1",
|
| 2436 |
"admin",
|
| 2437 |
"events",
|
| 2438 |
+
""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2439 |
],
|
| 2440 |
"query": [
|
| 2441 |
{
|
| 2442 |
"key": "page",
|
| 2443 |
+
"value": "1"
|
|
|
|
| 2444 |
},
|
| 2445 |
{
|
| 2446 |
"key": "limit",
|
| 2447 |
+
"value": "10"
|
|
|
|
| 2448 |
},
|
| 2449 |
{
|
| 2450 |
"key": "search",
|
| 2451 |
+
"value": ""
|
|
|
|
| 2452 |
},
|
| 2453 |
{
|
| 2454 |
"key": "sortBy",
|
| 2455 |
+
"value": "created_at"
|
|
|
|
| 2456 |
},
|
| 2457 |
{
|
| 2458 |
"key": "order",
|
| 2459 |
+
"value": "desc"
|
| 2460 |
+
},
|
| 2461 |
+
{
|
| 2462 |
+
"key": "status",
|
| 2463 |
+
"value": "",
|
| 2464 |
+
"disabled": true
|
| 2465 |
}
|
| 2466 |
]
|
| 2467 |
},
|
| 2468 |
+
"description": "Admin view: list all events with participant_count and exam_count. Supports pagination and search."
|
| 2469 |
},
|
| 2470 |
"response": []
|
| 2471 |
},
|
| 2472 |
{
|
| 2473 |
+
"name": "Create Event",
|
| 2474 |
"request": {
|
| 2475 |
+
"method": "POST",
|
| 2476 |
"header": [
|
| 2477 |
{
|
| 2478 |
"key": "Content-Type",
|
|
|
|
| 2487 |
],
|
| 2488 |
"body": {
|
| 2489 |
"mode": "raw",
|
| 2490 |
+
"raw": "{\n \"title\": \"National Olympiad 2026\",\n \"start_event\": \"2026-04-01T08:00:00Z\",\n \"end_event\": \"2026-04-02T17:00:00Z\",\n \"overview\": \"Annual national programming olympiad\",\n \"img_banner\": \"https://example.com/banner.jpg\",\n \"event_code\": \"NAT2026\",\n \"is_public\": true\n}"
|
| 2491 |
},
|
| 2492 |
"url": {
|
| 2493 |
+
"raw": "{{base_url}}/api/v1/admin/events/",
|
| 2494 |
"host": [
|
| 2495 |
"{{base_url}}"
|
| 2496 |
],
|
|
|
|
| 2499 |
"v1",
|
| 2500 |
"admin",
|
| 2501 |
"events",
|
| 2502 |
+
""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2503 |
]
|
| 2504 |
},
|
| 2505 |
+
"description": "Create a new event."
|
| 2506 |
},
|
| 2507 |
"response": []
|
| 2508 |
},
|
| 2509 |
{
|
| 2510 |
+
"name": "Update Event",
|
| 2511 |
"request": {
|
| 2512 |
+
"method": "PUT",
|
| 2513 |
"header": [
|
| 2514 |
+
{
|
| 2515 |
+
"key": "Content-Type",
|
| 2516 |
+
"value": "application/json",
|
| 2517 |
+
"type": "text"
|
| 2518 |
+
},
|
| 2519 |
{
|
| 2520 |
"key": "Authorization",
|
| 2521 |
"value": "Bearer {{access_token}}",
|
| 2522 |
"type": "text"
|
| 2523 |
}
|
| 2524 |
],
|
| 2525 |
+
"body": {
|
| 2526 |
+
"mode": "raw",
|
| 2527 |
+
"raw": "{\n \"title\": \"Updated Event Title\",\n \"overview\": \"Updated overview text\",\n \"is_public\": true\n}"
|
| 2528 |
+
},
|
| 2529 |
"url": {
|
| 2530 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id",
|
| 2531 |
"host": [
|
| 2532 |
"{{base_url}}"
|
| 2533 |
],
|
|
|
|
| 2536 |
"v1",
|
| 2537 |
"admin",
|
| 2538 |
"events",
|
| 2539 |
+
":event_id"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2540 |
],
|
| 2541 |
"variable": [
|
| 2542 |
{
|
| 2543 |
"key": "event_id",
|
| 2544 |
"value": "{{event_id}}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2545 |
}
|
| 2546 |
]
|
| 2547 |
},
|
| 2548 |
+
"description": "Update an existing event by ID."
|
| 2549 |
},
|
| 2550 |
"response": []
|
| 2551 |
+
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2552 |
{
|
| 2553 |
+
"name": "Delete Event",
|
| 2554 |
"request": {
|
| 2555 |
+
"method": "DELETE",
|
| 2556 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2557 |
{
|
| 2558 |
"key": "Authorization",
|
| 2559 |
"value": "Bearer {{access_token}}",
|
| 2560 |
"type": "text"
|
| 2561 |
}
|
| 2562 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2563 |
"url": {
|
| 2564 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id",
|
| 2565 |
"host": [
|
| 2566 |
"{{base_url}}"
|
| 2567 |
],
|
|
|
|
| 2569 |
"api",
|
| 2570 |
"v1",
|
| 2571 |
"admin",
|
| 2572 |
+
"events",
|
| 2573 |
+
":event_id"
|
| 2574 |
+
],
|
| 2575 |
+
"variable": [
|
| 2576 |
+
{
|
| 2577 |
+
"key": "event_id",
|
| 2578 |
+
"value": "{{event_id}}"
|
| 2579 |
+
}
|
| 2580 |
]
|
| 2581 |
},
|
| 2582 |
+
"description": "Delete an event by ID."
|
| 2583 |
},
|
| 2584 |
"response": []
|
| 2585 |
},
|
| 2586 |
{
|
| 2587 |
+
"name": "Participants - List",
|
| 2588 |
"request": {
|
| 2589 |
"method": "GET",
|
| 2590 |
"header": [
|
|
|
|
| 2595 |
}
|
| 2596 |
],
|
| 2597 |
"url": {
|
| 2598 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/participants?page=1&limit=10&search=&sortBy=assigned_at&order=desc",
|
| 2599 |
"host": [
|
| 2600 |
"{{base_url}}"
|
| 2601 |
],
|
|
|
|
| 2603 |
"api",
|
| 2604 |
"v1",
|
| 2605 |
"admin",
|
| 2606 |
+
"events",
|
| 2607 |
+
":event_id",
|
| 2608 |
+
"participants"
|
|
|
|
| 2609 |
],
|
| 2610 |
"variable": [
|
| 2611 |
{
|
| 2612 |
+
"key": "event_id",
|
| 2613 |
+
"value": "{{event_id}}"
|
| 2614 |
+
}
|
| 2615 |
+
],
|
| 2616 |
+
"query": [
|
| 2617 |
+
{
|
| 2618 |
+
"key": "page",
|
| 2619 |
+
"value": "1",
|
| 2620 |
+
"description": "Page number"
|
| 2621 |
+
},
|
| 2622 |
+
{
|
| 2623 |
+
"key": "limit",
|
| 2624 |
+
"value": "10",
|
| 2625 |
+
"description": "Items per page (max 100)"
|
| 2626 |
+
},
|
| 2627 |
+
{
|
| 2628 |
+
"key": "search",
|
| 2629 |
+
"value": "",
|
| 2630 |
+
"description": "Search by username / full name"
|
| 2631 |
+
},
|
| 2632 |
+
{
|
| 2633 |
+
"key": "sortBy",
|
| 2634 |
+
"value": "assigned_at",
|
| 2635 |
+
"description": "Sort field (assigned_at, username, full_name)"
|
| 2636 |
+
},
|
| 2637 |
+
{
|
| 2638 |
+
"key": "order",
|
| 2639 |
+
"value": "desc",
|
| 2640 |
+
"description": "Sort direction (asc / desc)"
|
| 2641 |
}
|
| 2642 |
]
|
| 2643 |
},
|
| 2644 |
+
"description": "List all participants (with account details) assigned to an event."
|
| 2645 |
},
|
| 2646 |
"response": []
|
| 2647 |
},
|
| 2648 |
{
|
| 2649 |
+
"name": "Candidates - List",
|
| 2650 |
"request": {
|
| 2651 |
+
"method": "GET",
|
| 2652 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2653 |
{
|
| 2654 |
"key": "Authorization",
|
| 2655 |
"value": "Bearer {{access_token}}",
|
| 2656 |
"type": "text"
|
| 2657 |
}
|
| 2658 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2659 |
"url": {
|
| 2660 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/candidate?page=1&limit=10&search=&sortBy=created_at&orderBy=desc",
|
| 2661 |
"host": [
|
| 2662 |
"{{base_url}}"
|
| 2663 |
],
|
|
|
|
| 2665 |
"api",
|
| 2666 |
"v1",
|
| 2667 |
"admin",
|
| 2668 |
+
"events",
|
| 2669 |
+
":event_id",
|
| 2670 |
+
"candidate"
|
| 2671 |
],
|
| 2672 |
"variable": [
|
| 2673 |
{
|
| 2674 |
+
"key": "event_id",
|
| 2675 |
+
"value": "{{event_id}}"
|
| 2676 |
+
}
|
| 2677 |
+
],
|
| 2678 |
+
"query": [
|
| 2679 |
+
{
|
| 2680 |
+
"key": "page",
|
| 2681 |
+
"value": "1",
|
| 2682 |
+
"description": "Page number"
|
| 2683 |
+
},
|
| 2684 |
+
{
|
| 2685 |
+
"key": "limit",
|
| 2686 |
+
"value": "10",
|
| 2687 |
+
"description": "Items per page (max 100)"
|
| 2688 |
+
},
|
| 2689 |
+
{
|
| 2690 |
+
"key": "search",
|
| 2691 |
+
"value": "",
|
| 2692 |
+
"description": "Search by username / full name"
|
| 2693 |
+
},
|
| 2694 |
+
{
|
| 2695 |
+
"key": "sortBy",
|
| 2696 |
+
"value": "created_at",
|
| 2697 |
+
"description": "Sort field (username, full_name, created_at)"
|
| 2698 |
+
},
|
| 2699 |
+
{
|
| 2700 |
+
"key": "orderBy",
|
| 2701 |
+
"value": "desc",
|
| 2702 |
+
"description": "Sort direction (asc / desc)"
|
| 2703 |
}
|
| 2704 |
]
|
| 2705 |
},
|
| 2706 |
+
"description": "List accounts that are not yet assigned to the event."
|
| 2707 |
},
|
| 2708 |
"response": []
|
| 2709 |
},
|
| 2710 |
{
|
| 2711 |
+
"name": "Participants - Add (Manual Assign)",
|
| 2712 |
"request": {
|
| 2713 |
+
"method": "POST",
|
| 2714 |
"header": [
|
| 2715 |
+
{
|
| 2716 |
+
"key": "Content-Type",
|
| 2717 |
+
"value": "application/json",
|
| 2718 |
+
"type": "text"
|
| 2719 |
+
},
|
| 2720 |
{
|
| 2721 |
"key": "Authorization",
|
| 2722 |
"value": "Bearer {{access_token}}",
|
| 2723 |
"type": "text"
|
| 2724 |
}
|
| 2725 |
],
|
| 2726 |
+
"body": {
|
| 2727 |
+
"mode": "raw",
|
| 2728 |
+
"raw": "{\n \"user_id\": \"{{user_id}}\"\n}"
|
| 2729 |
+
},
|
| 2730 |
"url": {
|
| 2731 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/participants",
|
| 2732 |
"host": [
|
| 2733 |
"{{base_url}}"
|
| 2734 |
],
|
|
|
|
| 2736 |
"api",
|
| 2737 |
"v1",
|
| 2738 |
"admin",
|
| 2739 |
+
"events",
|
| 2740 |
+
":event_id",
|
| 2741 |
+
"participants"
|
| 2742 |
],
|
| 2743 |
"variable": [
|
| 2744 |
{
|
| 2745 |
+
"key": "event_id",
|
| 2746 |
+
"value": "{{event_id}}"
|
| 2747 |
}
|
| 2748 |
]
|
| 2749 |
},
|
| 2750 |
+
"description": "Manually assign a user to an event. Bypasses payment."
|
| 2751 |
},
|
| 2752 |
"response": []
|
| 2753 |
},
|
| 2754 |
{
|
| 2755 |
+
"name": "Participants - Remove",
|
| 2756 |
"request": {
|
| 2757 |
+
"method": "DELETE",
|
| 2758 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2759 |
{
|
| 2760 |
"key": "Authorization",
|
| 2761 |
"value": "Bearer {{access_token}}",
|
| 2762 |
"type": "text"
|
| 2763 |
}
|
| 2764 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2765 |
"url": {
|
| 2766 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/participants/:user_id",
|
| 2767 |
"host": [
|
| 2768 |
"{{base_url}}"
|
| 2769 |
],
|
|
|
|
| 2771 |
"api",
|
| 2772 |
"v1",
|
| 2773 |
"admin",
|
| 2774 |
+
"events",
|
| 2775 |
+
":event_id",
|
| 2776 |
+
"participants",
|
| 2777 |
+
":user_id"
|
| 2778 |
+
],
|
| 2779 |
+
"variable": [
|
| 2780 |
+
{
|
| 2781 |
+
"key": "event_id",
|
| 2782 |
+
"value": "{{event_id}}"
|
| 2783 |
+
},
|
| 2784 |
+
{
|
| 2785 |
+
"key": "user_id",
|
| 2786 |
+
"value": "{{user_id}}"
|
| 2787 |
+
}
|
| 2788 |
]
|
| 2789 |
},
|
| 2790 |
+
"description": "Unassign a user from an event."
|
| 2791 |
},
|
| 2792 |
"response": []
|
| 2793 |
},
|
| 2794 |
{
|
| 2795 |
+
"name": "Exams - List Event Exams",
|
| 2796 |
"request": {
|
| 2797 |
+
"method": "GET",
|
| 2798 |
"header": [
|
| 2799 |
{
|
| 2800 |
"key": "Authorization",
|
|
|
|
| 2803 |
}
|
| 2804 |
],
|
| 2805 |
"url": {
|
| 2806 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/exams?page=1&limit=10&search=&sortBy=created_at&order=desc",
|
| 2807 |
"host": [
|
| 2808 |
"{{base_url}}"
|
| 2809 |
],
|
|
|
|
| 2811 |
"api",
|
| 2812 |
"v1",
|
| 2813 |
"admin",
|
| 2814 |
+
"events",
|
| 2815 |
+
":event_id",
|
| 2816 |
+
"exams"
|
| 2817 |
],
|
| 2818 |
"variable": [
|
| 2819 |
{
|
| 2820 |
+
"key": "event_id",
|
| 2821 |
+
"value": "{{event_id}}"
|
| 2822 |
+
}
|
| 2823 |
+
],
|
| 2824 |
+
"query": [
|
| 2825 |
+
{
|
| 2826 |
+
"key": "page",
|
| 2827 |
+
"value": "1",
|
| 2828 |
+
"description": "Page number"
|
| 2829 |
+
},
|
| 2830 |
+
{
|
| 2831 |
+
"key": "limit",
|
| 2832 |
+
"value": "10",
|
| 2833 |
+
"description": "Items per page (max 100)"
|
| 2834 |
+
},
|
| 2835 |
+
{
|
| 2836 |
+
"key": "search",
|
| 2837 |
+
"value": "",
|
| 2838 |
+
"description": "Search term"
|
| 2839 |
+
},
|
| 2840 |
+
{
|
| 2841 |
+
"key": "sortBy",
|
| 2842 |
+
"value": "created_at",
|
| 2843 |
+
"description": "Sort field (title, slug, created_at, duration)"
|
| 2844 |
+
},
|
| 2845 |
+
{
|
| 2846 |
+
"key": "order",
|
| 2847 |
+
"value": "desc",
|
| 2848 |
+
"description": "Sort direction (asc / desc)"
|
| 2849 |
}
|
| 2850 |
]
|
| 2851 |
},
|
| 2852 |
+
"description": "List all exams assigned to an event, with exam details."
|
| 2853 |
},
|
| 2854 |
"response": []
|
| 2855 |
},
|
| 2856 |
{
|
| 2857 |
+
"name": "Exams - List Exam Candidates",
|
| 2858 |
"request": {
|
| 2859 |
+
"method": "GET",
|
| 2860 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2861 |
{
|
| 2862 |
"key": "Authorization",
|
| 2863 |
"value": "Bearer {{access_token}}",
|
| 2864 |
"type": "text"
|
| 2865 |
}
|
| 2866 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2867 |
"url": {
|
| 2868 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/candidate?page=1&limit=10&search=&sortBy=created_at&orderBy=desc",
|
| 2869 |
"host": [
|
| 2870 |
"{{base_url}}"
|
| 2871 |
],
|
|
|
|
| 2873 |
"api",
|
| 2874 |
"v1",
|
| 2875 |
"admin",
|
| 2876 |
+
"events",
|
| 2877 |
+
":event_id",
|
| 2878 |
+
"exams",
|
| 2879 |
+
"candidate"
|
| 2880 |
+
],
|
| 2881 |
+
"variable": [
|
| 2882 |
+
{
|
| 2883 |
+
"key": "event_id",
|
| 2884 |
+
"value": "{{event_id}}"
|
| 2885 |
+
}
|
| 2886 |
+
],
|
| 2887 |
+
"query": [
|
| 2888 |
+
{
|
| 2889 |
+
"key": "page",
|
| 2890 |
+
"value": "1",
|
| 2891 |
+
"description": "Page number"
|
| 2892 |
+
},
|
| 2893 |
+
{
|
| 2894 |
+
"key": "limit",
|
| 2895 |
+
"value": "10",
|
| 2896 |
+
"description": "Items per page (max 100)"
|
| 2897 |
+
},
|
| 2898 |
+
{
|
| 2899 |
+
"key": "search",
|
| 2900 |
+
"value": "",
|
| 2901 |
+
"description": "Search by exam title / slug"
|
| 2902 |
+
},
|
| 2903 |
+
{
|
| 2904 |
+
"key": "sortBy",
|
| 2905 |
+
"value": "created_at",
|
| 2906 |
+
"description": "Sort field (title, slug, created_at, duration)"
|
| 2907 |
+
},
|
| 2908 |
+
{
|
| 2909 |
+
"key": "orderBy",
|
| 2910 |
+
"value": "desc",
|
| 2911 |
+
"description": "Sort direction (asc / desc)"
|
| 2912 |
+
}
|
| 2913 |
]
|
| 2914 |
},
|
| 2915 |
+
"description": "List exams that are not yet assigned to the event."
|
| 2916 |
},
|
| 2917 |
"response": []
|
| 2918 |
},
|
| 2919 |
{
|
| 2920 |
+
"name": "Exams - Remove Exam from Event",
|
| 2921 |
"request": {
|
| 2922 |
"method": "DELETE",
|
| 2923 |
"header": [
|
|
|
|
| 2928 |
}
|
| 2929 |
],
|
| 2930 |
"url": {
|
| 2931 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id",
|
| 2932 |
"host": [
|
| 2933 |
"{{base_url}}"
|
| 2934 |
],
|
|
|
|
| 2936 |
"api",
|
| 2937 |
"v1",
|
| 2938 |
"admin",
|
| 2939 |
+
"events",
|
| 2940 |
+
":event_id",
|
| 2941 |
+
"exams",
|
| 2942 |
+
":exam_id"
|
| 2943 |
],
|
| 2944 |
"variable": [
|
| 2945 |
{
|
| 2946 |
+
"key": "event_id",
|
| 2947 |
+
"value": "{{event_id}}"
|
| 2948 |
+
},
|
| 2949 |
+
{
|
| 2950 |
+
"key": "exam_id",
|
| 2951 |
+
"value": "{{exam_id}}"
|
| 2952 |
}
|
| 2953 |
]
|
| 2954 |
},
|
| 2955 |
+
"description": "Unassign an exam from an event."
|
| 2956 |
},
|
| 2957 |
"response": []
|
| 2958 |
},
|
| 2959 |
{
|
| 2960 |
+
"name": "Results - List Exam Results",
|
| 2961 |
"request": {
|
| 2962 |
+
"method": "GET",
|
| 2963 |
"header": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2964 |
{
|
| 2965 |
"key": "Authorization",
|
| 2966 |
"value": "Bearer {{access_token}}",
|
| 2967 |
"type": "text"
|
| 2968 |
}
|
| 2969 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2970 |
"url": {
|
| 2971 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id/results?page=1&limit=10&search=&sortBy=final_score&order=desc",
|
| 2972 |
"host": [
|
| 2973 |
"{{base_url}}"
|
| 2974 |
],
|
|
|
|
| 2976 |
"api",
|
| 2977 |
"v1",
|
| 2978 |
"admin",
|
| 2979 |
+
"events",
|
| 2980 |
+
":event_id",
|
| 2981 |
+
"exams",
|
| 2982 |
+
":exam_id",
|
| 2983 |
+
"results"
|
| 2984 |
+
],
|
| 2985 |
+
"variable": [
|
| 2986 |
+
{
|
| 2987 |
+
"key": "event_id",
|
| 2988 |
+
"value": "{{event_id}}"
|
| 2989 |
+
},
|
| 2990 |
+
{
|
| 2991 |
+
"key": "exam_id",
|
| 2992 |
+
"value": "{{exam_id}}"
|
| 2993 |
+
}
|
| 2994 |
+
],
|
| 2995 |
+
"query": [
|
| 2996 |
+
{
|
| 2997 |
+
"key": "page",
|
| 2998 |
+
"value": "1",
|
| 2999 |
+
"description": "Page number"
|
| 3000 |
+
},
|
| 3001 |
+
{
|
| 3002 |
+
"key": "limit",
|
| 3003 |
+
"value": "10",
|
| 3004 |
+
"description": "Items per page (max 100)"
|
| 3005 |
+
},
|
| 3006 |
+
{
|
| 3007 |
+
"key": "search",
|
| 3008 |
+
"value": "",
|
| 3009 |
+
"description": "Search by username / full name"
|
| 3010 |
+
},
|
| 3011 |
+
{
|
| 3012 |
+
"key": "sortBy",
|
| 3013 |
+
"value": "final_score",
|
| 3014 |
+
"description": "Sort field (final_score, created_at, username, full_name)"
|
| 3015 |
+
},
|
| 3016 |
+
{
|
| 3017 |
+
"key": "order",
|
| 3018 |
+
"value": "desc",
|
| 3019 |
+
"description": "Sort direction (asc / desc)"
|
| 3020 |
+
}
|
| 3021 |
]
|
| 3022 |
},
|
| 3023 |
+
"description": "List all participant results for a specific exam within an event."
|
| 3024 |
},
|
| 3025 |
"response": []
|
| 3026 |
},
|
| 3027 |
{
|
| 3028 |
+
"name": "Results - Edit Result",
|
| 3029 |
"request": {
|
| 3030 |
+
"method": "PUT",
|
| 3031 |
"header": [
|
| 3032 |
+
{
|
| 3033 |
+
"key": "Content-Type",
|
| 3034 |
+
"value": "application/json",
|
| 3035 |
+
"type": "text"
|
| 3036 |
+
},
|
| 3037 |
{
|
| 3038 |
"key": "Authorization",
|
| 3039 |
"value": "Bearer {{access_token}}",
|
| 3040 |
"type": "text"
|
| 3041 |
}
|
| 3042 |
],
|
| 3043 |
+
"body": {
|
| 3044 |
+
"mode": "raw",
|
| 3045 |
+
"raw": "{\n \"final_score\": 95.5\n}"
|
| 3046 |
+
},
|
| 3047 |
"url": {
|
| 3048 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id/results/:result_id",
|
| 3049 |
"host": [
|
| 3050 |
"{{base_url}}"
|
| 3051 |
],
|
|
|
|
| 3053 |
"api",
|
| 3054 |
"v1",
|
| 3055 |
"admin",
|
| 3056 |
+
"events",
|
| 3057 |
+
":event_id",
|
| 3058 |
+
"exams",
|
| 3059 |
+
":exam_id",
|
| 3060 |
+
"results",
|
| 3061 |
+
":result_id"
|
| 3062 |
],
|
| 3063 |
"variable": [
|
| 3064 |
{
|
| 3065 |
+
"key": "event_id",
|
| 3066 |
+
"value": "{{event_id}}"
|
| 3067 |
+
},
|
| 3068 |
+
{
|
| 3069 |
+
"key": "exam_id",
|
| 3070 |
+
"value": "{{exam_id}}"
|
| 3071 |
+
},
|
| 3072 |
+
{
|
| 3073 |
+
"key": "result_id",
|
| 3074 |
+
"value": "{{result_id}}"
|
| 3075 |
}
|
| 3076 |
]
|
| 3077 |
},
|
| 3078 |
+
"description": "Edit the final score of a participant's exam result."
|
| 3079 |
},
|
| 3080 |
"response": []
|
| 3081 |
},
|
| 3082 |
{
|
| 3083 |
+
"name": "Results - Delete Result",
|
| 3084 |
"request": {
|
| 3085 |
+
"method": "DELETE",
|
| 3086 |
"header": [
|
| 3087 |
{
|
| 3088 |
"key": "Authorization",
|
|
|
|
| 3091 |
}
|
| 3092 |
],
|
| 3093 |
"url": {
|
| 3094 |
+
"raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id/results/:result_id",
|
| 3095 |
"host": [
|
| 3096 |
"{{base_url}}"
|
| 3097 |
],
|
|
|
|
| 3099 |
"api",
|
| 3100 |
"v1",
|
| 3101 |
"admin",
|
| 3102 |
+
"events",
|
| 3103 |
+
":event_id",
|
| 3104 |
+
"exams",
|
| 3105 |
+
":exam_id",
|
| 3106 |
+
"results",
|
| 3107 |
+
":result_id"
|
| 3108 |
],
|
| 3109 |
"variable": [
|
| 3110 |
{
|
| 3111 |
+
"key": "event_id",
|
| 3112 |
+
"value": "{{event_id}}"
|
| 3113 |
+
},
|
| 3114 |
+
{
|
| 3115 |
+
"key": "exam_id",
|
| 3116 |
+
"value": "{{exam_id}}"
|
| 3117 |
+
},
|
| 3118 |
+
{
|
| 3119 |
+
"key": "result_id",
|
| 3120 |
+
"value": "{{result_id}}"
|
| 3121 |
}
|
| 3122 |
]
|
| 3123 |
},
|
| 3124 |
+
"description": "Delete a participant's exam result."
|
| 3125 |
},
|
| 3126 |
"response": []
|
| 3127 |
}
|
|
|
|
| 4716 |
"key": "material_id",
|
| 4717 |
"value": "",
|
| 4718 |
"type": "string"
|
| 4719 |
+
},
|
| 4720 |
+
{
|
| 4721 |
+
"key": "problemset_id",
|
| 4722 |
+
"value": "",
|
| 4723 |
+
"type": "string"
|
| 4724 |
+
},
|
| 4725 |
+
{
|
| 4726 |
+
"key": "question_id",
|
| 4727 |
+
"value": "",
|
| 4728 |
+
"type": "string"
|
| 4729 |
}
|
| 4730 |
]
|
| 4731 |
+
}
|
controllers/academy_controller.go
CHANGED
|
@@ -29,12 +29,18 @@ type AcademyController interface {
|
|
| 29 |
|
| 30 |
// Material
|
| 31 |
GetMaterial(ctx *gin.Context)
|
|
|
|
|
|
|
| 32 |
CreateMaterial(ctx *gin.Context)
|
|
|
|
| 33 |
DeleteMaterial(ctx *gin.Context)
|
| 34 |
|
| 35 |
// Content
|
| 36 |
CreateContent(ctx *gin.Context)
|
| 37 |
GetContent(ctx *gin.Context)
|
|
|
|
|
|
|
|
|
|
| 38 |
DeleteContent(ctx *gin.Context)
|
| 39 |
|
| 40 |
// Progress
|
|
@@ -76,7 +82,7 @@ func (c *academyController) GetAcademy(ctx *gin.Context) {
|
|
| 76 |
// @Param id path string true "Academy ID"
|
| 77 |
// @Success 200 {object} dto.SuccessResponse[entity.Academy]
|
| 78 |
// @Failure 400 {object} dto.ErrorResponse
|
| 79 |
-
// @Router /api/v1/
|
| 80 |
func (c *academyController) GetAcademyDetail(ctx *gin.Context) {
|
| 81 |
id := ParseUUID(ctx, "id")
|
| 82 |
res, err := c.academyService.GetAcademyDetail(ctx.Request.Context(), id)
|
|
@@ -183,7 +189,7 @@ func (c *academyController) ListAcademy(ctx *gin.Context) {
|
|
| 183 |
// @Success 200 {object} dto.SuccessResponse[entity.Academy]
|
| 184 |
// @Failure 400 {object} dto.ErrorResponse
|
| 185 |
// @Security BearerAuth
|
| 186 |
-
// @Router /api/v1/
|
| 187 |
func (c *academyController) CreateAcademy(ctx *gin.Context) {
|
| 188 |
req := RequestJSON[dto.CreateAcademyRequest](ctx)
|
| 189 |
res, err := c.academyService.CreateAcademy(ctx.Request.Context(), req)
|
|
@@ -201,7 +207,7 @@ func (c *academyController) CreateAcademy(ctx *gin.Context) {
|
|
| 201 |
// @Success 200 {object} dto.SuccessResponse[entity.Academy]
|
| 202 |
// @Failure 400 {object} dto.ErrorResponse
|
| 203 |
// @Security BearerAuth
|
| 204 |
-
// @Router /api/v1/
|
| 205 |
func (c *academyController) UpdateAcademy(ctx *gin.Context) {
|
| 206 |
id := ParseUUID(ctx, "id")
|
| 207 |
req := RequestJSON[dto.UpdateAcademyRequest](ctx)
|
|
@@ -219,7 +225,7 @@ func (c *academyController) UpdateAcademy(ctx *gin.Context) {
|
|
| 219 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 220 |
// @Failure 400 {object} dto.ErrorResponse
|
| 221 |
// @Security BearerAuth
|
| 222 |
-
// @Router /api/v1/
|
| 223 |
func (c *academyController) DeleteAcademy(ctx *gin.Context) {
|
| 224 |
id := ParseUUID(ctx, "id")
|
| 225 |
err := c.academyService.DeleteAcademy(ctx.Request.Context(), id)
|
|
@@ -246,6 +252,40 @@ func (c *academyController) GetMaterial(ctx *gin.Context) {
|
|
| 246 |
ResponseJSON(ctx, gin.H{"academy_slug": academySlug, "material_slug": materialSlug}, res, err)
|
| 247 |
}
|
| 248 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
// CreateMaterial godoc
|
| 250 |
// @Summary Create Material
|
| 251 |
// @Description Create a new material for an academy
|
|
@@ -256,13 +296,32 @@ func (c *academyController) GetMaterial(ctx *gin.Context) {
|
|
| 256 |
// @Success 200 {object} dto.SuccessResponse[entity.AcademyMaterial]
|
| 257 |
// @Failure 400 {object} dto.ErrorResponse
|
| 258 |
// @Security BearerAuth
|
| 259 |
-
// @Router /api/v1/
|
| 260 |
func (c *academyController) CreateMaterial(ctx *gin.Context) {
|
| 261 |
req := RequestJSON[dto.CreateMaterialRequest](ctx)
|
| 262 |
res, err := c.academyService.CreateMaterial(ctx.Request.Context(), req)
|
| 263 |
ResponseJSON(ctx, req, res, err)
|
| 264 |
}
|
| 265 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
// DeleteMaterial godoc
|
| 267 |
// @Summary Delete Material
|
| 268 |
// @Description Delete an existing material
|
|
@@ -273,7 +332,7 @@ func (c *academyController) CreateMaterial(ctx *gin.Context) {
|
|
| 273 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 274 |
// @Failure 400 {object} dto.ErrorResponse
|
| 275 |
// @Security BearerAuth
|
| 276 |
-
// @Router /api/v1/
|
| 277 |
|
| 278 |
func (c *academyController) DeleteMaterial(ctx *gin.Context) {
|
| 279 |
id := ParseUUID(ctx, "id")
|
|
@@ -311,6 +370,40 @@ func (c *academyController) GetContent(ctx *gin.Context) {
|
|
| 311 |
ResponseJSON(ctx, gin.H{"academy_slug": academySlug, "material_slug": materialSlug, "content_order": order}, res, err)
|
| 312 |
}
|
| 313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
// CreateContent godoc
|
| 315 |
// @Summary Create Content
|
| 316 |
// @Description Create a new content for a material
|
|
@@ -321,13 +414,32 @@ func (c *academyController) GetContent(ctx *gin.Context) {
|
|
| 321 |
// @Success 200 {object} dto.SuccessResponse[entity.AcademyContent]
|
| 322 |
// @Failure 400 {object} dto.ErrorResponse
|
| 323 |
// @Security BearerAuth
|
| 324 |
-
// @Router /api/v1/
|
| 325 |
func (c *academyController) CreateContent(ctx *gin.Context) {
|
| 326 |
req := RequestJSON[dto.CreateContentRequest](ctx)
|
| 327 |
res, err := c.academyService.CreateContent(ctx.Request.Context(), req)
|
| 328 |
ResponseJSON(ctx, req, res, err)
|
| 329 |
}
|
| 330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
// DeleteContent godoc
|
| 332 |
// @Summary Delete Content
|
| 333 |
// @Description Delete an existing content
|
|
@@ -338,7 +450,7 @@ func (c *academyController) CreateContent(ctx *gin.Context) {
|
|
| 338 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 339 |
// @Failure 400 {object} dto.ErrorResponse
|
| 340 |
// @Security BearerAuth
|
| 341 |
-
// @Router /api/v1/
|
| 342 |
func (c *academyController) DeleteContent(ctx *gin.Context) {
|
| 343 |
id := ParseUUID(ctx, "id")
|
| 344 |
err := c.academyService.DeleteContent(ctx.Request.Context(), id)
|
|
@@ -423,7 +535,7 @@ func (c *academyController) JoinAcademyByCode(ctx *gin.Context) {
|
|
| 423 |
// @Success 200 {object} dto.SuccessResponse[entity.AcademyAssign]
|
| 424 |
// @Failure 400 {object} dto.ErrorResponse
|
| 425 |
// @Security BearerAuth
|
| 426 |
-
// @Router /api/v1/
|
| 427 |
func (c *academyController) AssignAccountToAcademy(ctx *gin.Context) {
|
| 428 |
req := RequestJSON[dto.AssignRequest](ctx)
|
| 429 |
academyId, errA := uuid.Parse(req.AcademyId)
|
|
@@ -448,7 +560,7 @@ func (c *academyController) AssignAccountToAcademy(ctx *gin.Context) {
|
|
| 448 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 449 |
// @Failure 400 {object} dto.ErrorResponse
|
| 450 |
// @Security BearerAuth
|
| 451 |
-
// @Router /api/v1/
|
| 452 |
func (c *academyController) UnassignAccountFromAcademy(ctx *gin.Context) {
|
| 453 |
id := ParseUUID(ctx, "id")
|
| 454 |
err := c.academyService.UnassignAccountFromAcademy(ctx.Request.Context(), id)
|
|
@@ -465,7 +577,7 @@ func (c *academyController) UnassignAccountFromAcademy(ctx *gin.Context) {
|
|
| 465 |
// @Success 200 {object} dto.SuccessResponse[[]entity.AcademyAssign]
|
| 466 |
// @Failure 400 {object} dto.ErrorResponse
|
| 467 |
// @Security BearerAuth
|
| 468 |
-
// @Router /api/v1/
|
| 469 |
func (c *academyController) ListAssignmentsByAcademy(ctx *gin.Context) {
|
| 470 |
academyId := ParseUUID(ctx, "academy_id")
|
| 471 |
res, err := c.academyService.ListAssignmentsByAcademy(ctx.Request.Context(), academyId)
|
|
|
|
| 29 |
|
| 30 |
// Material
|
| 31 |
GetMaterial(ctx *gin.Context)
|
| 32 |
+
ListMaterialsByAcademy(ctx *gin.Context)
|
| 33 |
+
GetMaterialDetail(ctx *gin.Context)
|
| 34 |
CreateMaterial(ctx *gin.Context)
|
| 35 |
+
UpdateMaterial(ctx *gin.Context)
|
| 36 |
DeleteMaterial(ctx *gin.Context)
|
| 37 |
|
| 38 |
// Content
|
| 39 |
CreateContent(ctx *gin.Context)
|
| 40 |
GetContent(ctx *gin.Context)
|
| 41 |
+
ListContentsByMaterial(ctx *gin.Context)
|
| 42 |
+
GetContentDetail(ctx *gin.Context)
|
| 43 |
+
UpdateContent(ctx *gin.Context)
|
| 44 |
DeleteContent(ctx *gin.Context)
|
| 45 |
|
| 46 |
// Progress
|
|
|
|
| 82 |
// @Param id path string true "Academy ID"
|
| 83 |
// @Success 200 {object} dto.SuccessResponse[entity.Academy]
|
| 84 |
// @Failure 400 {object} dto.ErrorResponse
|
| 85 |
+
// @Router /api/v1/admin_academy/id/{id}/detail [get]
|
| 86 |
func (c *academyController) GetAcademyDetail(ctx *gin.Context) {
|
| 87 |
id := ParseUUID(ctx, "id")
|
| 88 |
res, err := c.academyService.GetAcademyDetail(ctx.Request.Context(), id)
|
|
|
|
| 189 |
// @Success 200 {object} dto.SuccessResponse[entity.Academy]
|
| 190 |
// @Failure 400 {object} dto.ErrorResponse
|
| 191 |
// @Security BearerAuth
|
| 192 |
+
// @Router /api/v1/admin_academy [post]
|
| 193 |
func (c *academyController) CreateAcademy(ctx *gin.Context) {
|
| 194 |
req := RequestJSON[dto.CreateAcademyRequest](ctx)
|
| 195 |
res, err := c.academyService.CreateAcademy(ctx.Request.Context(), req)
|
|
|
|
| 207 |
// @Success 200 {object} dto.SuccessResponse[entity.Academy]
|
| 208 |
// @Failure 400 {object} dto.ErrorResponse
|
| 209 |
// @Security BearerAuth
|
| 210 |
+
// @Router /api/v1/admin_academy/id/{id} [put]
|
| 211 |
func (c *academyController) UpdateAcademy(ctx *gin.Context) {
|
| 212 |
id := ParseUUID(ctx, "id")
|
| 213 |
req := RequestJSON[dto.UpdateAcademyRequest](ctx)
|
|
|
|
| 225 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 226 |
// @Failure 400 {object} dto.ErrorResponse
|
| 227 |
// @Security BearerAuth
|
| 228 |
+
// @Router /api/v1/admin_academy/id/{id} [delete]
|
| 229 |
func (c *academyController) DeleteAcademy(ctx *gin.Context) {
|
| 230 |
id := ParseUUID(ctx, "id")
|
| 231 |
err := c.academyService.DeleteAcademy(ctx.Request.Context(), id)
|
|
|
|
| 252 |
ResponseJSON(ctx, gin.H{"academy_slug": academySlug, "material_slug": materialSlug}, res, err)
|
| 253 |
}
|
| 254 |
|
| 255 |
+
// ListMaterialsByAcademy godoc
|
| 256 |
+
// @Summary List Materials by Academy
|
| 257 |
+
// @Description Retrieve a list of materials for a specific academy
|
| 258 |
+
// @Tags Material
|
| 259 |
+
// @Accept json
|
| 260 |
+
// @Produce json
|
| 261 |
+
// @Param id path string true "Academy ID"
|
| 262 |
+
// @Success 200 {object} dto.SuccessResponse[[]entity.AcademyMaterial]
|
| 263 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 264 |
+
// @Security BearerAuth
|
| 265 |
+
// @Router /api/v1/admin_academy/id/{id}/materials [get]
|
| 266 |
+
func (c *academyController) ListMaterialsByAcademy(ctx *gin.Context) {
|
| 267 |
+
id := ParseUUID(ctx, "id")
|
| 268 |
+
res, err := c.academyService.ListMaterialsByAcademy(ctx.Request.Context(), id)
|
| 269 |
+
ResponseJSON(ctx, gin.H{"academy_id": id}, res, err)
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// GetMaterialDetail godoc
|
| 273 |
+
// @Summary Get Material Detail by ID
|
| 274 |
+
// @Description Retrieve detailed material information using its ID
|
| 275 |
+
// @Tags Material
|
| 276 |
+
// @Accept json
|
| 277 |
+
// @Produce json
|
| 278 |
+
// @Param id path string true "Material ID"
|
| 279 |
+
// @Success 200 {object} dto.SuccessResponse[entity.AcademyMaterial]
|
| 280 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 281 |
+
// @Security BearerAuth
|
| 282 |
+
// @Router /api/v1/admin_academy/materials/id/{id}/detail [get]
|
| 283 |
+
func (c *academyController) GetMaterialDetail(ctx *gin.Context) {
|
| 284 |
+
id := ParseUUID(ctx, "id")
|
| 285 |
+
res, err := c.academyService.GetMaterialDetail(ctx.Request.Context(), id)
|
| 286 |
+
ResponseJSON(ctx, gin.H{"id": id}, res, err)
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
// CreateMaterial godoc
|
| 290 |
// @Summary Create Material
|
| 291 |
// @Description Create a new material for an academy
|
|
|
|
| 296 |
// @Success 200 {object} dto.SuccessResponse[entity.AcademyMaterial]
|
| 297 |
// @Failure 400 {object} dto.ErrorResponse
|
| 298 |
// @Security BearerAuth
|
| 299 |
+
// @Router /api/v1/admin_academy/materials [post]
|
| 300 |
func (c *academyController) CreateMaterial(ctx *gin.Context) {
|
| 301 |
req := RequestJSON[dto.CreateMaterialRequest](ctx)
|
| 302 |
res, err := c.academyService.CreateMaterial(ctx.Request.Context(), req)
|
| 303 |
ResponseJSON(ctx, req, res, err)
|
| 304 |
}
|
| 305 |
|
| 306 |
+
// UpdateMaterial godoc
|
| 307 |
+
// @Summary Update Material
|
| 308 |
+
// @Description Update an existing material
|
| 309 |
+
// @Tags Material
|
| 310 |
+
// @Accept json
|
| 311 |
+
// @Produce json
|
| 312 |
+
// @Param id path string true "Material ID"
|
| 313 |
+
// @Param request body dto.UpdateMaterialRequest true "Update Material Request"
|
| 314 |
+
// @Success 200 {object} dto.SuccessResponse[entity.AcademyMaterial]
|
| 315 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 316 |
+
// @Security BearerAuth
|
| 317 |
+
// @Router /api/v1/admin_academy/materials/id/{id} [put]
|
| 318 |
+
func (c *academyController) UpdateMaterial(ctx *gin.Context) {
|
| 319 |
+
id := ParseUUID(ctx, "id")
|
| 320 |
+
req := RequestJSON[dto.UpdateMaterialRequest](ctx)
|
| 321 |
+
res, err := c.academyService.UpdateMaterial(ctx.Request.Context(), id, req)
|
| 322 |
+
ResponseJSON(ctx, req, res, err)
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
// DeleteMaterial godoc
|
| 326 |
// @Summary Delete Material
|
| 327 |
// @Description Delete an existing material
|
|
|
|
| 332 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 333 |
// @Failure 400 {object} dto.ErrorResponse
|
| 334 |
// @Security BearerAuth
|
| 335 |
+
// @Router /api/v1/admin_academy/materials/{id} [delete]
|
| 336 |
|
| 337 |
func (c *academyController) DeleteMaterial(ctx *gin.Context) {
|
| 338 |
id := ParseUUID(ctx, "id")
|
|
|
|
| 370 |
ResponseJSON(ctx, gin.H{"academy_slug": academySlug, "material_slug": materialSlug, "content_order": order}, res, err)
|
| 371 |
}
|
| 372 |
|
| 373 |
+
// ListContentsByMaterial godoc
|
| 374 |
+
// @Summary List Contents by Material
|
| 375 |
+
// @Description Retrieve a list of contents for a specific material
|
| 376 |
+
// @Tags Content
|
| 377 |
+
// @Accept json
|
| 378 |
+
// @Produce json
|
| 379 |
+
// @Param id path string true "Material ID"
|
| 380 |
+
// @Success 200 {object} dto.SuccessResponse[[]entity.AcademyContent]
|
| 381 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 382 |
+
// @Security BearerAuth
|
| 383 |
+
// @Router /api/v1/admin_academy/materials/id/{id}/contents [get]
|
| 384 |
+
func (c *academyController) ListContentsByMaterial(ctx *gin.Context) {
|
| 385 |
+
id := ParseUUID(ctx, "id")
|
| 386 |
+
res, err := c.academyService.ListContentsByMaterial(ctx.Request.Context(), id)
|
| 387 |
+
ResponseJSON(ctx, gin.H{"material_id": id}, res, err)
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
// GetContentDetail godoc
|
| 391 |
+
// @Summary Get Content Detail by ID
|
| 392 |
+
// @Description Retrieve detailed content information using its ID
|
| 393 |
+
// @Tags Content
|
| 394 |
+
// @Accept json
|
| 395 |
+
// @Produce json
|
| 396 |
+
// @Param id path string true "Content ID"
|
| 397 |
+
// @Success 200 {object} dto.SuccessResponse[entity.AcademyContent]
|
| 398 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 399 |
+
// @Security BearerAuth
|
| 400 |
+
// @Router /api/v1/admin_academy/contents/id/{id}/detail [get]
|
| 401 |
+
func (c *academyController) GetContentDetail(ctx *gin.Context) {
|
| 402 |
+
id := ParseUUID(ctx, "id")
|
| 403 |
+
res, err := c.academyService.GetContentDetail(ctx.Request.Context(), id)
|
| 404 |
+
ResponseJSON(ctx, gin.H{"id": id}, res, err)
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
// CreateContent godoc
|
| 408 |
// @Summary Create Content
|
| 409 |
// @Description Create a new content for a material
|
|
|
|
| 414 |
// @Success 200 {object} dto.SuccessResponse[entity.AcademyContent]
|
| 415 |
// @Failure 400 {object} dto.ErrorResponse
|
| 416 |
// @Security BearerAuth
|
| 417 |
+
// @Router /api/v1/admin_academy/contents [post]
|
| 418 |
func (c *academyController) CreateContent(ctx *gin.Context) {
|
| 419 |
req := RequestJSON[dto.CreateContentRequest](ctx)
|
| 420 |
res, err := c.academyService.CreateContent(ctx.Request.Context(), req)
|
| 421 |
ResponseJSON(ctx, req, res, err)
|
| 422 |
}
|
| 423 |
|
| 424 |
+
// UpdateContent godoc
|
| 425 |
+
// @Summary Update Content
|
| 426 |
+
// @Description Update an existing content
|
| 427 |
+
// @Tags Content
|
| 428 |
+
// @Accept json
|
| 429 |
+
// @Produce json
|
| 430 |
+
// @Param id path string true "Content ID"
|
| 431 |
+
// @Param request body dto.UpdateContentRequest true "Update Content Request"
|
| 432 |
+
// @Success 200 {object} dto.SuccessResponse[entity.AcademyContent]
|
| 433 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 434 |
+
// @Security BearerAuth
|
| 435 |
+
// @Router /api/v1/admin_academy/contents/id/{id} [put]
|
| 436 |
+
func (c *academyController) UpdateContent(ctx *gin.Context) {
|
| 437 |
+
id := ParseUUID(ctx, "id")
|
| 438 |
+
req := RequestJSON[dto.UpdateContentRequest](ctx)
|
| 439 |
+
res, err := c.academyService.UpdateContent(ctx.Request.Context(), id, req)
|
| 440 |
+
ResponseJSON(ctx, req, res, err)
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
// DeleteContent godoc
|
| 444 |
// @Summary Delete Content
|
| 445 |
// @Description Delete an existing content
|
|
|
|
| 450 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 451 |
// @Failure 400 {object} dto.ErrorResponse
|
| 452 |
// @Security BearerAuth
|
| 453 |
+
// @Router /api/v1/admin_academy/contents/{id} [delete]
|
| 454 |
func (c *academyController) DeleteContent(ctx *gin.Context) {
|
| 455 |
id := ParseUUID(ctx, "id")
|
| 456 |
err := c.academyService.DeleteContent(ctx.Request.Context(), id)
|
|
|
|
| 535 |
// @Success 200 {object} dto.SuccessResponse[entity.AcademyAssign]
|
| 536 |
// @Failure 400 {object} dto.ErrorResponse
|
| 537 |
// @Security BearerAuth
|
| 538 |
+
// @Router /api/v1/admin_academy/assign [post]
|
| 539 |
func (c *academyController) AssignAccountToAcademy(ctx *gin.Context) {
|
| 540 |
req := RequestJSON[dto.AssignRequest](ctx)
|
| 541 |
academyId, errA := uuid.Parse(req.AcademyId)
|
|
|
|
| 560 |
// @Success 200 {object} dto.SuccessResponse[any]
|
| 561 |
// @Failure 400 {object} dto.ErrorResponse
|
| 562 |
// @Security BearerAuth
|
| 563 |
+
// @Router /api/v1/admin_academy/assign/{id} [delete]
|
| 564 |
func (c *academyController) UnassignAccountFromAcademy(ctx *gin.Context) {
|
| 565 |
id := ParseUUID(ctx, "id")
|
| 566 |
err := c.academyService.UnassignAccountFromAcademy(ctx.Request.Context(), id)
|
|
|
|
| 577 |
// @Success 200 {object} dto.SuccessResponse[[]entity.AcademyAssign]
|
| 578 |
// @Failure 400 {object} dto.ErrorResponse
|
| 579 |
// @Security BearerAuth
|
| 580 |
+
// @Router /api/v1/admin_academy/assign/{academy_id} [get]
|
| 581 |
func (c *academyController) ListAssignmentsByAcademy(ctx *gin.Context) {
|
| 582 |
academyId := ParseUUID(ctx, "academy_id")
|
| 583 |
res, err := c.academyService.ListAssignmentsByAcademy(ctx.Request.Context(), academyId)
|
controllers/admin_academy_controller.go
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package controllers
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"abdanhafidz.com/go-boilerplate/models/dto"
|
| 5 |
+
http_error "abdanhafidz.com/go-boilerplate/models/error"
|
| 6 |
+
"abdanhafidz.com/go-boilerplate/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
"github.com/google/uuid"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
type AdminAcademyController interface {
|
| 12 |
+
CreateAcademy(ctx *gin.Context)
|
| 13 |
+
GetAcademyDetail(ctx *gin.Context)
|
| 14 |
+
UpdateAcademy(ctx *gin.Context)
|
| 15 |
+
DeleteAcademy(ctx *gin.Context)
|
| 16 |
+
|
| 17 |
+
ListMaterialsByAcademy(ctx *gin.Context)
|
| 18 |
+
GetMaterialDetail(ctx *gin.Context)
|
| 19 |
+
CreateMaterial(ctx *gin.Context)
|
| 20 |
+
UpdateMaterial(ctx *gin.Context)
|
| 21 |
+
DeleteMaterial(ctx *gin.Context)
|
| 22 |
+
|
| 23 |
+
ListContentsByMaterial(ctx *gin.Context)
|
| 24 |
+
GetContentDetail(ctx *gin.Context)
|
| 25 |
+
CreateContent(ctx *gin.Context)
|
| 26 |
+
UpdateContent(ctx *gin.Context)
|
| 27 |
+
DeleteContent(ctx *gin.Context)
|
| 28 |
+
|
| 29 |
+
AssignAccountToAcademy(ctx *gin.Context)
|
| 30 |
+
UnassignAccountFromAcademy(ctx *gin.Context)
|
| 31 |
+
ListAssignmentsByAcademy(ctx *gin.Context)
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
type adminAcademyController struct {
|
| 35 |
+
service services.AdminAcademyService
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
func NewAdminAcademyController(service services.AdminAcademyService) AdminAcademyController {
|
| 39 |
+
return &adminAcademyController{service: service}
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// CreateAcademy godoc
|
| 43 |
+
// @Summary Create Academy
|
| 44 |
+
// @Description Create a new academy
|
| 45 |
+
// @Tags Admin Academy
|
| 46 |
+
// @Accept json
|
| 47 |
+
// @Produce json
|
| 48 |
+
// @Param request body dto.CreateAcademyRequest true "Create Academy Request"
|
| 49 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 50 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 51 |
+
// @Security BearerAuth
|
| 52 |
+
// @Router /api/v1/admin_academy [post]
|
| 53 |
+
func (c *adminAcademyController) CreateAcademy(ctx *gin.Context) {
|
| 54 |
+
req := RequestJSON[dto.CreateAcademyRequest](ctx)
|
| 55 |
+
res, err := c.service.CreateAcademy(ctx.Request.Context(), req)
|
| 56 |
+
ResponseJSON(ctx, req, res, err)
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
// GetAcademyDetail godoc
|
| 60 |
+
// @Summary Get Academy Detail by ID
|
| 61 |
+
// @Description Retrieve detailed academy information using its ID
|
| 62 |
+
// @Tags Admin Academy
|
| 63 |
+
// @Accept json
|
| 64 |
+
// @Produce json
|
| 65 |
+
// @Param id path string true "Academy ID"
|
| 66 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 67 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 68 |
+
// @Security BearerAuth
|
| 69 |
+
// @Router /api/v1/admin_academy/id/{id}/detail [get]
|
| 70 |
+
func (c *adminAcademyController) GetAcademyDetail(ctx *gin.Context) {
|
| 71 |
+
id := ParseUUID(ctx, "id")
|
| 72 |
+
res, err := c.service.GetAcademyDetail(ctx.Request.Context(), id)
|
| 73 |
+
ResponseJSON(ctx, gin.H{"id": id}, res, err)
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
// UpdateAcademy godoc
|
| 77 |
+
// @Summary Update Academy
|
| 78 |
+
// @Description Update an existing academy
|
| 79 |
+
// @Tags Admin Academy
|
| 80 |
+
// @Accept json
|
| 81 |
+
// @Produce json
|
| 82 |
+
// @Param id path string true "Academy ID"
|
| 83 |
+
// @Param request body dto.UpdateAcademyRequest true "Update Academy Request"
|
| 84 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 85 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 86 |
+
// @Security BearerAuth
|
| 87 |
+
// @Router /api/v1/admin_academy/id/{id} [put]
|
| 88 |
+
func (c *adminAcademyController) UpdateAcademy(ctx *gin.Context) {
|
| 89 |
+
id := ParseUUID(ctx, "id")
|
| 90 |
+
req := RequestJSON[dto.UpdateAcademyRequest](ctx)
|
| 91 |
+
res, err := c.service.UpdateAcademy(ctx.Request.Context(), id, req)
|
| 92 |
+
ResponseJSON(ctx, req, res, err)
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
// DeleteAcademy godoc
|
| 96 |
+
// @Summary Delete Academy
|
| 97 |
+
// @Description Delete an existing academy
|
| 98 |
+
// @Tags Admin Academy
|
| 99 |
+
// @Accept json
|
| 100 |
+
// @Produce json
|
| 101 |
+
// @Param id path string true "Academy ID"
|
| 102 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 103 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 104 |
+
// @Security BearerAuth
|
| 105 |
+
// @Router /api/v1/admin_academy/id/{id} [delete]
|
| 106 |
+
func (c *adminAcademyController) DeleteAcademy(ctx *gin.Context) {
|
| 107 |
+
id := ParseUUID(ctx, "id")
|
| 108 |
+
err := c.service.DeleteAcademy(ctx.Request.Context(), id)
|
| 109 |
+
ResponseJSON(ctx, gin.H{"id": id}, gin.H{"deleted": true}, err)
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
// ListMaterialsByAcademy godoc
|
| 113 |
+
// @Summary List Materials by Academy
|
| 114 |
+
// @Description Retrieve a list of materials for a specific academy
|
| 115 |
+
// @Tags Admin Academy
|
| 116 |
+
// @Accept json
|
| 117 |
+
// @Produce json
|
| 118 |
+
// @Param id path string true "Academy ID"
|
| 119 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 120 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 121 |
+
// @Security BearerAuth
|
| 122 |
+
// @Router /api/v1/admin_academy/id/{id}/materials [get]
|
| 123 |
+
func (c *adminAcademyController) ListMaterialsByAcademy(ctx *gin.Context) {
|
| 124 |
+
id := ParseUUID(ctx, "id")
|
| 125 |
+
res, err := c.service.ListMaterialsByAcademy(ctx.Request.Context(), id)
|
| 126 |
+
ResponseJSON(ctx, gin.H{"academy_id": id}, res, err)
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
// GetMaterialDetail godoc
|
| 130 |
+
// @Summary Get Material Detail by ID
|
| 131 |
+
// @Description Retrieve detailed material information using its ID
|
| 132 |
+
// @Tags Admin Academy
|
| 133 |
+
// @Accept json
|
| 134 |
+
// @Produce json
|
| 135 |
+
// @Param id path string true "Material ID"
|
| 136 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 137 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 138 |
+
// @Security BearerAuth
|
| 139 |
+
// @Router /api/v1/admin_academy/materials/id/{id}/detail [get]
|
| 140 |
+
func (c *adminAcademyController) GetMaterialDetail(ctx *gin.Context) {
|
| 141 |
+
id := ParseUUID(ctx, "id")
|
| 142 |
+
res, err := c.service.GetMaterialDetail(ctx.Request.Context(), id)
|
| 143 |
+
ResponseJSON(ctx, gin.H{"id": id}, res, err)
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
// CreateMaterial godoc
|
| 147 |
+
// @Summary Create Material
|
| 148 |
+
// @Description Create a new material for an academy
|
| 149 |
+
// @Tags Admin Academy
|
| 150 |
+
// @Accept json
|
| 151 |
+
// @Produce json
|
| 152 |
+
// @Param request body dto.CreateMaterialRequest true "Create Material Request"
|
| 153 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 154 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 155 |
+
// @Security BearerAuth
|
| 156 |
+
// @Router /api/v1/admin_academy/materials [post]
|
| 157 |
+
func (c *adminAcademyController) CreateMaterial(ctx *gin.Context) {
|
| 158 |
+
req := RequestJSON[dto.CreateMaterialRequest](ctx)
|
| 159 |
+
res, err := c.service.CreateMaterial(ctx.Request.Context(), req)
|
| 160 |
+
ResponseJSON(ctx, req, res, err)
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
// UpdateMaterial godoc
|
| 164 |
+
// @Summary Update Material
|
| 165 |
+
// @Description Update an existing material
|
| 166 |
+
// @Tags Admin Academy
|
| 167 |
+
// @Accept json
|
| 168 |
+
// @Produce json
|
| 169 |
+
// @Param id path string true "Material ID"
|
| 170 |
+
// @Param request body dto.UpdateMaterialRequest true "Update Material Request"
|
| 171 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 172 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 173 |
+
// @Security BearerAuth
|
| 174 |
+
// @Router /api/v1/admin_academy/materials/id/{id} [put]
|
| 175 |
+
func (c *adminAcademyController) UpdateMaterial(ctx *gin.Context) {
|
| 176 |
+
id := ParseUUID(ctx, "id")
|
| 177 |
+
req := RequestJSON[dto.UpdateMaterialRequest](ctx)
|
| 178 |
+
res, err := c.service.UpdateMaterial(ctx.Request.Context(), id, req)
|
| 179 |
+
ResponseJSON(ctx, req, res, err)
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
// DeleteMaterial godoc
|
| 183 |
+
// @Summary Delete Material
|
| 184 |
+
// @Description Delete an existing material
|
| 185 |
+
// @Tags Admin Academy
|
| 186 |
+
// @Accept json
|
| 187 |
+
// @Produce json
|
| 188 |
+
// @Param id path string true "Material ID"
|
| 189 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 190 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 191 |
+
// @Security BearerAuth
|
| 192 |
+
// @Router /api/v1/admin_academy/materials/{id} [delete]
|
| 193 |
+
func (c *adminAcademyController) DeleteMaterial(ctx *gin.Context) {
|
| 194 |
+
id := ParseUUID(ctx, "id")
|
| 195 |
+
err := c.service.DeleteMaterial(ctx.Request.Context(), id)
|
| 196 |
+
ResponseJSON(ctx, gin.H{"id": id}, gin.H{"deleted": true}, err)
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
// ListContentsByMaterial godoc
|
| 200 |
+
// @Summary List Contents by Material
|
| 201 |
+
// @Description Retrieve a list of contents for a specific material
|
| 202 |
+
// @Tags Admin Academy
|
| 203 |
+
// @Accept json
|
| 204 |
+
// @Produce json
|
| 205 |
+
// @Param id path string true "Material ID"
|
| 206 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 207 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 208 |
+
// @Security BearerAuth
|
| 209 |
+
// @Router /api/v1/admin_academy/materials/id/{id}/contents [get]
|
| 210 |
+
func (c *adminAcademyController) ListContentsByMaterial(ctx *gin.Context) {
|
| 211 |
+
id := ParseUUID(ctx, "id")
|
| 212 |
+
res, err := c.service.ListContentsByMaterial(ctx.Request.Context(), id)
|
| 213 |
+
ResponseJSON(ctx, gin.H{"material_id": id}, res, err)
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
// GetContentDetail godoc
|
| 217 |
+
// @Summary Get Content Detail by ID
|
| 218 |
+
// @Description Retrieve detailed content information using its ID
|
| 219 |
+
// @Tags Admin Academy
|
| 220 |
+
// @Accept json
|
| 221 |
+
// @Produce json
|
| 222 |
+
// @Param id path string true "Content ID"
|
| 223 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 224 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 225 |
+
// @Security BearerAuth
|
| 226 |
+
// @Router /api/v1/admin_academy/contents/id/{id}/detail [get]
|
| 227 |
+
func (c *adminAcademyController) GetContentDetail(ctx *gin.Context) {
|
| 228 |
+
id := ParseUUID(ctx, "id")
|
| 229 |
+
res, err := c.service.GetContentDetail(ctx.Request.Context(), id)
|
| 230 |
+
ResponseJSON(ctx, gin.H{"id": id}, res, err)
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
// CreateContent godoc
|
| 234 |
+
// @Summary Create Content
|
| 235 |
+
// @Description Create a new content for a material
|
| 236 |
+
// @Tags Admin Academy
|
| 237 |
+
// @Accept json
|
| 238 |
+
// @Produce json
|
| 239 |
+
// @Param request body dto.CreateContentRequest true "Create Content Request"
|
| 240 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 241 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 242 |
+
// @Security BearerAuth
|
| 243 |
+
// @Router /api/v1/admin_academy/contents [post]
|
| 244 |
+
func (c *adminAcademyController) CreateContent(ctx *gin.Context) {
|
| 245 |
+
req := RequestJSON[dto.CreateContentRequest](ctx)
|
| 246 |
+
res, err := c.service.CreateContent(ctx.Request.Context(), req)
|
| 247 |
+
ResponseJSON(ctx, req, res, err)
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
// UpdateContent godoc
|
| 251 |
+
// @Summary Update Content
|
| 252 |
+
// @Description Update an existing content
|
| 253 |
+
// @Tags Admin Academy
|
| 254 |
+
// @Accept json
|
| 255 |
+
// @Produce json
|
| 256 |
+
// @Param id path string true "Content ID"
|
| 257 |
+
// @Param request body dto.UpdateContentRequest true "Update Content Request"
|
| 258 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 259 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 260 |
+
// @Security BearerAuth
|
| 261 |
+
// @Router /api/v1/admin_academy/contents/id/{id} [put]
|
| 262 |
+
func (c *adminAcademyController) UpdateContent(ctx *gin.Context) {
|
| 263 |
+
id := ParseUUID(ctx, "id")
|
| 264 |
+
req := RequestJSON[dto.UpdateContentRequest](ctx)
|
| 265 |
+
res, err := c.service.UpdateContent(ctx.Request.Context(), id, req)
|
| 266 |
+
ResponseJSON(ctx, req, res, err)
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
// DeleteContent godoc
|
| 270 |
+
// @Summary Delete Content
|
| 271 |
+
// @Description Delete an existing content
|
| 272 |
+
// @Tags Admin Academy
|
| 273 |
+
// @Accept json
|
| 274 |
+
// @Produce json
|
| 275 |
+
// @Param id path string true "Content ID"
|
| 276 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 277 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 278 |
+
// @Security BearerAuth
|
| 279 |
+
// @Router /api/v1/admin_academy/contents/{id} [delete]
|
| 280 |
+
func (c *adminAcademyController) DeleteContent(ctx *gin.Context) {
|
| 281 |
+
id := ParseUUID(ctx, "id")
|
| 282 |
+
err := c.service.DeleteContent(ctx.Request.Context(), id)
|
| 283 |
+
ResponseJSON(ctx, gin.H{"id": id}, gin.H{"deleted": true}, err)
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
// AssignAccountToAcademy godoc
|
| 287 |
+
// @Summary Assign Account to Academy
|
| 288 |
+
// @Description Assign an account to an academy
|
| 289 |
+
// @Tags Admin Academy
|
| 290 |
+
// @Accept json
|
| 291 |
+
// @Produce json
|
| 292 |
+
// @Param request body dto.AssignRequest true "Assign Account to Academy Request"
|
| 293 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 294 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 295 |
+
// @Security BearerAuth
|
| 296 |
+
// @Router /api/v1/admin_academy/assign [post]
|
| 297 |
+
func (c *adminAcademyController) AssignAccountToAcademy(ctx *gin.Context) {
|
| 298 |
+
req := RequestJSON[dto.AssignRequest](ctx)
|
| 299 |
+
academyId, errA := uuid.Parse(req.AcademyId)
|
| 300 |
+
accountId, errB := uuid.Parse(req.AccountId)
|
| 301 |
+
if errA != nil || errB != nil {
|
| 302 |
+
ResponseJSON[any, any](ctx, nil, nil, http_error.BAD_REQUEST_ERROR)
|
| 303 |
+
return
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
res, err := c.service.AssignAccountToAcademy(ctx.Request.Context(), academyId, accountId)
|
| 307 |
+
ResponseJSON(ctx, req, res, err)
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
// UnassignAccountFromAcademy godoc
|
| 311 |
+
// @Summary Unassign Account from Academy
|
| 312 |
+
// @Description Unassign an account from an academy
|
| 313 |
+
// @Tags Admin Academy
|
| 314 |
+
// @Accept json
|
| 315 |
+
// @Produce json
|
| 316 |
+
// @Param id path string true "Assignment ID"
|
| 317 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 318 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 319 |
+
// @Security BearerAuth
|
| 320 |
+
// @Router /api/v1/admin_academy/assign/{id} [delete]
|
| 321 |
+
func (c *adminAcademyController) UnassignAccountFromAcademy(ctx *gin.Context) {
|
| 322 |
+
id := ParseUUID(ctx, "id")
|
| 323 |
+
err := c.service.UnassignAccountFromAcademy(ctx.Request.Context(), id)
|
| 324 |
+
ResponseJSON(ctx, gin.H{"id": id}, gin.H{"deleted": true}, err)
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
// ListAssignmentsByAcademy godoc
|
| 328 |
+
// @Summary List Assignments by Academy
|
| 329 |
+
// @Description Retrieve a list of assignments for a specific academy
|
| 330 |
+
// @Tags Admin Academy
|
| 331 |
+
// @Accept json
|
| 332 |
+
// @Produce json
|
| 333 |
+
// @Param academy_id path string true "Academy ID"
|
| 334 |
+
// @Success 200 {object} dto.SuccessResponse[any]
|
| 335 |
+
// @Failure 400 {object} dto.ErrorResponse
|
| 336 |
+
// @Security BearerAuth
|
| 337 |
+
// @Router /api/v1/admin_academy/assign/{academy_id} [get]
|
| 338 |
+
func (c *adminAcademyController) ListAssignmentsByAcademy(ctx *gin.Context) {
|
| 339 |
+
academyId := ParseUUID(ctx, "academy_id")
|
| 340 |
+
res, err := c.service.ListAssignmentsByAcademy(ctx.Request.Context(), academyId)
|
| 341 |
+
ResponseJSON(ctx, gin.H{"academy_id": academyId}, res, err)
|
| 342 |
+
}
|
controllers/admin_statistic_controller.go
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package controllers
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"strconv"
|
| 5 |
+
|
| 6 |
+
"abdanhafidz.com/go-boilerplate/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
"github.com/google/uuid"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
type AdminStatisticController interface {
|
| 12 |
+
GetSummary(ctx *gin.Context)
|
| 13 |
+
GetMonthlyGrowth(ctx *gin.Context)
|
| 14 |
+
GetEventOverview(ctx *gin.Context)
|
| 15 |
+
GetEventDetail(ctx *gin.Context)
|
| 16 |
+
GetExamOverview(ctx *gin.Context)
|
| 17 |
+
GetExamDetail(ctx *gin.Context)
|
| 18 |
+
GetAcademyOverview(ctx *gin.Context)
|
| 19 |
+
GetAcademyDetail(ctx *gin.Context)
|
| 20 |
+
GetProblemSetOverview(ctx *gin.Context)
|
| 21 |
+
GetProblemSetDetail(ctx *gin.Context)
|
| 22 |
+
GetQuestionOverview(ctx *gin.Context)
|
| 23 |
+
GetQuestionDetail(ctx *gin.Context)
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
type adminStatisticController struct {
|
| 27 |
+
adminStatisticService services.AdminStatisticService
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
func NewAdminStatisticController(adminStatisticService services.AdminStatisticService) AdminStatisticController {
|
| 31 |
+
return &adminStatisticController{adminStatisticService: adminStatisticService}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
// GetSummary godoc
|
| 35 |
+
// @Summary Admin: Get Statistics Summary
|
| 36 |
+
// @Description Retrieve aggregate statistics for dashboard cards such as users, academies, events, exams, problemsets, attempts, and payment metrics
|
| 37 |
+
// @Tags AdminStatistic
|
| 38 |
+
// @Accept json
|
| 39 |
+
// @Produce json
|
| 40 |
+
// @Security BearerAuth
|
| 41 |
+
// @Success 200 {object} dto.SuccessResponse[dto.AdminStatisticSummary]
|
| 42 |
+
// @Failure 401 {object} dto.ErrorResponse
|
| 43 |
+
// @Failure 403 {object} dto.ErrorResponse
|
| 44 |
+
// @Failure 500 {object} dto.ErrorResponse
|
| 45 |
+
// @Router /api/v1/admin/statistics/summary [get]
|
| 46 |
+
func (c *adminStatisticController) GetSummary(ctx *gin.Context) {
|
| 47 |
+
summary, err := c.adminStatisticService.GetSummary(ctx.Request.Context())
|
| 48 |
+
ResponseJSON(ctx, gin.H{}, summary, err)
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
// GetMonthlyGrowth godoc
|
| 52 |
+
// @Summary Admin: Get Monthly Growth Statistics
|
| 53 |
+
// @Description Retrieve monthly growth trend for users, academies, events, exams, and problemsets
|
| 54 |
+
// @Tags AdminStatistic
|
| 55 |
+
// @Accept json
|
| 56 |
+
// @Produce json
|
| 57 |
+
// @Security BearerAuth
|
| 58 |
+
// @Param months query int false "How many months to include" default(6)
|
| 59 |
+
// @Success 200 {object} dto.SuccessResponse[[]dto.AdminStatisticMonthlyGrowth]
|
| 60 |
+
// @Failure 401 {object} dto.ErrorResponse
|
| 61 |
+
// @Failure 403 {object} dto.ErrorResponse
|
| 62 |
+
// @Failure 500 {object} dto.ErrorResponse
|
| 63 |
+
// @Router /api/v1/admin/statistics/monthly-growth [get]
|
| 64 |
+
func (c *adminStatisticController) GetMonthlyGrowth(ctx *gin.Context) {
|
| 65 |
+
months, _ := strconv.Atoi(ctx.DefaultQuery("months", "6"))
|
| 66 |
+
if months < 1 {
|
| 67 |
+
months = 6
|
| 68 |
+
}
|
| 69 |
+
if months > 24 {
|
| 70 |
+
months = 24
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
result, err := c.adminStatisticService.GetMonthlyGrowth(ctx.Request.Context(), months)
|
| 74 |
+
meta := gin.H{"months": months}
|
| 75 |
+
ResponseJSON(ctx, meta, result, err)
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
// GetEventOverview godoc
|
| 79 |
+
// @Summary Admin: Get Event Statistics Overview
|
| 80 |
+
// @Description Aggregate statistics for all events
|
| 81 |
+
// @Tags AdminStatistic
|
| 82 |
+
// @Accept json
|
| 83 |
+
// @Produce json
|
| 84 |
+
// @Security BearerAuth
|
| 85 |
+
// @Router /api/v1/admin/statistics/event [get]
|
| 86 |
+
func (c *adminStatisticController) GetEventOverview(ctx *gin.Context) {
|
| 87 |
+
result, err := c.adminStatisticService.GetEventOverview(ctx.Request.Context())
|
| 88 |
+
ResponseJSON(ctx, gin.H{}, result, err)
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
// GetEventDetail godoc
|
| 92 |
+
// @Summary Admin: Get Event Statistics Detail
|
| 93 |
+
// @Description Aggregate statistics for a single event
|
| 94 |
+
// @Tags AdminStatistic
|
| 95 |
+
// @Accept json
|
| 96 |
+
// @Produce json
|
| 97 |
+
// @Security BearerAuth
|
| 98 |
+
// @Param event_id path string true "Event ID"
|
| 99 |
+
// @Router /api/v1/admin/statistics/event/{event_id} [get]
|
| 100 |
+
func (c *adminStatisticController) GetEventDetail(ctx *gin.Context) {
|
| 101 |
+
eventID := ParseUUID(ctx, "event_id")
|
| 102 |
+
if eventID == uuid.Nil {
|
| 103 |
+
return
|
| 104 |
+
}
|
| 105 |
+
result, err := c.adminStatisticService.GetEventDetail(ctx.Request.Context(), eventID)
|
| 106 |
+
ResponseJSON(ctx, gin.H{"event_id": eventID}, result, err)
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
// GetExamOverview godoc
|
| 110 |
+
// @Summary Admin: Get Exam Statistics Overview
|
| 111 |
+
// @Description Aggregate statistics for all exams
|
| 112 |
+
// @Tags AdminStatistic
|
| 113 |
+
// @Accept json
|
| 114 |
+
// @Produce json
|
| 115 |
+
// @Security BearerAuth
|
| 116 |
+
// @Router /api/v1/admin/statistics/exam [get]
|
| 117 |
+
func (c *adminStatisticController) GetExamOverview(ctx *gin.Context) {
|
| 118 |
+
result, err := c.adminStatisticService.GetExamOverview(ctx.Request.Context())
|
| 119 |
+
ResponseJSON(ctx, gin.H{}, result, err)
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
// GetExamDetail godoc
|
| 123 |
+
// @Summary Admin: Get Exam Statistics Detail
|
| 124 |
+
// @Description Aggregate statistics for a single exam
|
| 125 |
+
// @Tags AdminStatistic
|
| 126 |
+
// @Accept json
|
| 127 |
+
// @Produce json
|
| 128 |
+
// @Security BearerAuth
|
| 129 |
+
// @Param exam_id path string true "Exam ID"
|
| 130 |
+
// @Router /api/v1/admin/statistics/exam/{exam_id} [get]
|
| 131 |
+
func (c *adminStatisticController) GetExamDetail(ctx *gin.Context) {
|
| 132 |
+
examID := ParseUUID(ctx, "exam_id")
|
| 133 |
+
if examID == uuid.Nil {
|
| 134 |
+
return
|
| 135 |
+
}
|
| 136 |
+
result, err := c.adminStatisticService.GetExamDetail(ctx.Request.Context(), examID)
|
| 137 |
+
ResponseJSON(ctx, gin.H{"exam_id": examID}, result, err)
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
// GetAcademyOverview godoc
|
| 141 |
+
// @Summary Admin: Get Academy Statistics Overview
|
| 142 |
+
// @Description Aggregate statistics for all academies
|
| 143 |
+
// @Tags AdminStatistic
|
| 144 |
+
// @Accept json
|
| 145 |
+
// @Produce json
|
| 146 |
+
// @Security BearerAuth
|
| 147 |
+
// @Router /api/v1/admin/statistics/academy [get]
|
| 148 |
+
func (c *adminStatisticController) GetAcademyOverview(ctx *gin.Context) {
|
| 149 |
+
result, err := c.adminStatisticService.GetAcademyOverview(ctx.Request.Context())
|
| 150 |
+
ResponseJSON(ctx, gin.H{}, result, err)
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
// GetAcademyDetail godoc
|
| 154 |
+
// @Summary Admin: Get Academy Statistics Detail
|
| 155 |
+
// @Description Aggregate statistics for a single academy
|
| 156 |
+
// @Tags AdminStatistic
|
| 157 |
+
// @Accept json
|
| 158 |
+
// @Produce json
|
| 159 |
+
// @Security BearerAuth
|
| 160 |
+
// @Param academy_id path string true "Academy ID"
|
| 161 |
+
// @Router /api/v1/admin/statistics/academy/{academy_id} [get]
|
| 162 |
+
func (c *adminStatisticController) GetAcademyDetail(ctx *gin.Context) {
|
| 163 |
+
academyID := ParseUUID(ctx, "academy_id")
|
| 164 |
+
if academyID == uuid.Nil {
|
| 165 |
+
return
|
| 166 |
+
}
|
| 167 |
+
result, err := c.adminStatisticService.GetAcademyDetail(ctx.Request.Context(), academyID)
|
| 168 |
+
ResponseJSON(ctx, gin.H{"academy_id": academyID}, result, err)
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
// GetProblemSetOverview godoc
|
| 172 |
+
// @Summary Admin: Get ProblemSet Statistics Overview
|
| 173 |
+
// @Description Aggregate statistics for all problemsets
|
| 174 |
+
// @Tags AdminStatistic
|
| 175 |
+
// @Accept json
|
| 176 |
+
// @Produce json
|
| 177 |
+
// @Security BearerAuth
|
| 178 |
+
// @Router /api/v1/admin/statistics/problemset [get]
|
| 179 |
+
func (c *adminStatisticController) GetProblemSetOverview(ctx *gin.Context) {
|
| 180 |
+
result, err := c.adminStatisticService.GetProblemSetOverview(ctx.Request.Context())
|
| 181 |
+
ResponseJSON(ctx, gin.H{}, result, err)
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
// GetProblemSetDetail godoc
|
| 185 |
+
// @Summary Admin: Get ProblemSet Statistics Detail
|
| 186 |
+
// @Description Aggregate statistics for a single problemset
|
| 187 |
+
// @Tags AdminStatistic
|
| 188 |
+
// @Accept json
|
| 189 |
+
// @Produce json
|
| 190 |
+
// @Security BearerAuth
|
| 191 |
+
// @Param problemset_id path string true "ProblemSet ID"
|
| 192 |
+
// @Router /api/v1/admin/statistics/problemset/{problemset_id} [get]
|
| 193 |
+
func (c *adminStatisticController) GetProblemSetDetail(ctx *gin.Context) {
|
| 194 |
+
problemSetID := ParseUUID(ctx, "problemset_id")
|
| 195 |
+
if problemSetID == uuid.Nil {
|
| 196 |
+
return
|
| 197 |
+
}
|
| 198 |
+
result, err := c.adminStatisticService.GetProblemSetDetail(ctx.Request.Context(), problemSetID)
|
| 199 |
+
ResponseJSON(ctx, gin.H{"problemset_id": problemSetID}, result, err)
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
// GetQuestionOverview godoc
|
| 203 |
+
// @Summary Admin: Get Question Statistics Overview
|
| 204 |
+
// @Description Aggregate statistics for all questions
|
| 205 |
+
// @Tags AdminStatistic
|
| 206 |
+
// @Accept json
|
| 207 |
+
// @Produce json
|
| 208 |
+
// @Security BearerAuth
|
| 209 |
+
// @Router /api/v1/admin/statistics/question [get]
|
| 210 |
+
func (c *adminStatisticController) GetQuestionOverview(ctx *gin.Context) {
|
| 211 |
+
result, err := c.adminStatisticService.GetQuestionOverview(ctx.Request.Context())
|
| 212 |
+
ResponseJSON(ctx, gin.H{}, result, err)
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
// GetQuestionDetail godoc
|
| 216 |
+
// @Summary Admin: Get Question Statistics Detail
|
| 217 |
+
// @Description Aggregate statistics for a single question
|
| 218 |
+
// @Tags AdminStatistic
|
| 219 |
+
// @Accept json
|
| 220 |
+
// @Produce json
|
| 221 |
+
// @Security BearerAuth
|
| 222 |
+
// @Param question_id path string true "Question ID"
|
| 223 |
+
// @Router /api/v1/admin/statistics/question/{question_id} [get]
|
| 224 |
+
func (c *adminStatisticController) GetQuestionDetail(ctx *gin.Context) {
|
| 225 |
+
questionID := ParseUUID(ctx, "question_id")
|
| 226 |
+
if questionID == uuid.Nil {
|
| 227 |
+
return
|
| 228 |
+
}
|
| 229 |
+
result, err := c.adminStatisticService.GetQuestionDetail(ctx.Request.Context(), questionID)
|
| 230 |
+
ResponseJSON(ctx, gin.H{"question_id": questionID}, result, err)
|
| 231 |
+
}
|
controllers/controller.go
CHANGED
|
@@ -18,11 +18,24 @@ func ParseAccountId(ctx *gin.Context) uuid.UUID {
|
|
| 18 |
}
|
| 19 |
|
| 20 |
func ParseUUID(ctx *gin.Context, attrName string) uuid.UUID {
|
| 21 |
-
uuidRaw
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
uuidParsed, err := utils.ToUUID(uuidRaw)
|
| 23 |
|
| 24 |
if err != nil {
|
| 25 |
-
ResponseJSON(ctx, gin.H{"id":
|
|
|
|
| 26 |
return uuid.UUID{}
|
| 27 |
}
|
| 28 |
return uuidParsed
|
|
|
|
| 18 |
}
|
| 19 |
|
| 20 |
func ParseUUID(ctx *gin.Context, attrName string) uuid.UUID {
|
| 21 |
+
uuidRaw := ctx.Param(attrName)
|
| 22 |
+
if uuidRaw == "" {
|
| 23 |
+
if fromCtx, ok := ctx.Get(attrName); ok {
|
| 24 |
+
uuidParsed, err := utils.ToUUID(fromCtx)
|
| 25 |
+
if err == nil {
|
| 26 |
+
return uuidParsed
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
ResponseJSON(ctx, gin.H{"id": uuidRaw}, uuid.UUID{}, http_error.BAD_REQUEST_ERROR)
|
| 30 |
+
ctx.Abort()
|
| 31 |
+
return uuid.UUID{}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
uuidParsed, err := utils.ToUUID(uuidRaw)
|
| 35 |
|
| 36 |
if err != nil {
|
| 37 |
+
ResponseJSON(ctx, gin.H{"id": uuidRaw}, uuid.UUID{}, http_error.BAD_REQUEST_ERROR)
|
| 38 |
+
ctx.Abort()
|
| 39 |
return uuid.UUID{}
|
| 40 |
}
|
| 41 |
return uuidParsed
|
models/dto/academy_dto.go
CHANGED
|
@@ -35,6 +35,17 @@ type CreateContentRequest struct {
|
|
| 35 |
Contents string `json:"contents"`
|
| 36 |
}
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
// ================= RESPONSE DTOs =================
|
| 39 |
|
| 40 |
type AcademyProgressResponse struct {
|
|
|
|
| 35 |
Contents string `json:"contents"`
|
| 36 |
}
|
| 37 |
|
| 38 |
+
type UpdateMaterialRequest struct {
|
| 39 |
+
Title string `json:"title"`
|
| 40 |
+
Slug string `json:"slug"`
|
| 41 |
+
Description string `json:"description"`
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
type UpdateContentRequest struct {
|
| 45 |
+
Title string `json:"title"`
|
| 46 |
+
Contents string `json:"contents"`
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
// ================= RESPONSE DTOs =================
|
| 50 |
|
| 51 |
type AcademyProgressResponse struct {
|
models/dto/admin_statistic_dto.go
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package dto
|
| 2 |
+
|
| 3 |
+
type AdminStatisticSummary struct {
|
| 4 |
+
TotalUsers int64 `json:"total_users"`
|
| 5 |
+
TotalAdmins int64 `json:"total_admins"`
|
| 6 |
+
TotalSuperAdmins int64 `json:"total_super_admins"`
|
| 7 |
+
TotalAcademies int64 `json:"total_academies"`
|
| 8 |
+
TotalEvents int64 `json:"total_events"`
|
| 9 |
+
TotalExams int64 `json:"total_exams"`
|
| 10 |
+
TotalProblemSets int64 `json:"total_problemsets"`
|
| 11 |
+
TotalQuestions int64 `json:"total_questions"`
|
| 12 |
+
TotalEventParticipants int64 `json:"total_event_participants"`
|
| 13 |
+
TotalAcademyParticipants int64 `json:"total_academy_participants"`
|
| 14 |
+
TotalEventExamAssignments int64 `json:"total_event_exam_assignments"`
|
| 15 |
+
TotalAcademyExamAssignments int64 `json:"total_academy_exam_assignments"`
|
| 16 |
+
TotalEventExamAttempts int64 `json:"total_event_exam_attempts"`
|
| 17 |
+
TotalAcademyExamAttempts int64 `json:"total_academy_exam_attempts"`
|
| 18 |
+
TotalEventResults int64 `json:"total_event_results"`
|
| 19 |
+
TotalAcademyResults int64 `json:"total_academy_results"`
|
| 20 |
+
TotalPaidEventTransactions int64 `json:"total_paid_event_transactions"`
|
| 21 |
+
TotalPaidAcademyTransactions int64 `json:"total_paid_academy_transactions"`
|
| 22 |
+
PaidEventRevenue float64 `json:"paid_event_revenue"`
|
| 23 |
+
PaidAcademyRevenue float64 `json:"paid_academy_revenue"`
|
| 24 |
+
TotalPaidRevenue float64 `json:"total_paid_revenue"`
|
| 25 |
+
AverageParticipantsPerEvent float64 `json:"avg_participants_per_event"`
|
| 26 |
+
AverageExamsPerEvent float64 `json:"avg_exams_per_event"`
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
type AdminStatisticMonthlyGrowth struct {
|
| 30 |
+
Month string `json:"month"`
|
| 31 |
+
NewUsers int64 `json:"new_users"`
|
| 32 |
+
NewAcademies int64 `json:"new_academies"`
|
| 33 |
+
NewEvents int64 `json:"new_events"`
|
| 34 |
+
NewExams int64 `json:"new_exams"`
|
| 35 |
+
NewProblemSets int64 `json:"new_problemsets"`
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
type AdminEventStatisticOverview struct {
|
| 39 |
+
TotalEvents int64 `json:"total_events"`
|
| 40 |
+
TotalParticipants int64 `json:"total_participants"`
|
| 41 |
+
TotalExamAssignments int64 `json:"total_exam_assignments"`
|
| 42 |
+
TotalExamAttempts int64 `json:"total_exam_attempts"`
|
| 43 |
+
TotalResults int64 `json:"total_results"`
|
| 44 |
+
TotalPaidTransactions int64 `json:"total_paid_transactions"`
|
| 45 |
+
TotalPaidRevenue float64 `json:"total_paid_revenue"`
|
| 46 |
+
AvgParticipantsPerEvent float64 `json:"avg_participants_per_event"`
|
| 47 |
+
AvgExamsPerEvent float64 `json:"avg_exams_per_event"`
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
type AdminEventStatisticDetail struct {
|
| 51 |
+
EventID string `json:"event_id"`
|
| 52 |
+
ParticipantCount int64 `json:"participant_count"`
|
| 53 |
+
ExamAssignmentCount int64 `json:"exam_assignment_count"`
|
| 54 |
+
ExamAttemptCount int64 `json:"exam_attempt_count"`
|
| 55 |
+
ResultCount int64 `json:"result_count"`
|
| 56 |
+
PaidTransactionCount int64 `json:"paid_transaction_count"`
|
| 57 |
+
PaidRevenue float64 `json:"paid_revenue"`
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
type AdminExamStatisticOverview struct {
|
| 61 |
+
TotalExams int64 `json:"total_exams"`
|
| 62 |
+
TotalEventAssignments int64 `json:"total_event_assignments"`
|
| 63 |
+
TotalAcademyAssignments int64 `json:"total_academy_assignments"`
|
| 64 |
+
TotalProblemSetAssignments int64 `json:"total_problemset_assignments"`
|
| 65 |
+
TotalEventAttempts int64 `json:"total_event_attempts"`
|
| 66 |
+
TotalAcademyAttempts int64 `json:"total_academy_attempts"`
|
| 67 |
+
TotalEventResults int64 `json:"total_event_results"`
|
| 68 |
+
TotalAcademyResults int64 `json:"total_academy_results"`
|
| 69 |
+
AvgProblemSetsPerExam float64 `json:"avg_problemsets_per_exam"`
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
type AdminExamStatisticDetail struct {
|
| 73 |
+
ExamID string `json:"exam_id"`
|
| 74 |
+
EventAssignmentCount int64 `json:"event_assignment_count"`
|
| 75 |
+
AcademyAssignmentCount int64 `json:"academy_assignment_count"`
|
| 76 |
+
ProblemSetAssignmentCount int64 `json:"problemset_assignment_count"`
|
| 77 |
+
EventAttemptCount int64 `json:"event_attempt_count"`
|
| 78 |
+
AcademyAttemptCount int64 `json:"academy_attempt_count"`
|
| 79 |
+
EventResultCount int64 `json:"event_result_count"`
|
| 80 |
+
AcademyResultCount int64 `json:"academy_result_count"`
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
type AdminAcademyStatisticOverview struct {
|
| 84 |
+
TotalAcademies int64 `json:"total_academies"`
|
| 85 |
+
TotalParticipants int64 `json:"total_participants"`
|
| 86 |
+
TotalExamAssignments int64 `json:"total_exam_assignments"`
|
| 87 |
+
TotalExamAttempts int64 `json:"total_exam_attempts"`
|
| 88 |
+
TotalResults int64 `json:"total_results"`
|
| 89 |
+
TotalPaidTransactions int64 `json:"total_paid_transactions"`
|
| 90 |
+
TotalPaidRevenue float64 `json:"total_paid_revenue"`
|
| 91 |
+
AvgParticipantsPerAcademy float64 `json:"avg_participants_per_academy"`
|
| 92 |
+
AvgExamsPerAcademy float64 `json:"avg_exams_per_academy"`
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
type AdminAcademyStatisticDetail struct {
|
| 96 |
+
AcademyID string `json:"academy_id"`
|
| 97 |
+
MaterialCount int64 `json:"material_count"`
|
| 98 |
+
ParticipantCount int64 `json:"participant_count"`
|
| 99 |
+
ExamAssignmentCount int64 `json:"exam_assignment_count"`
|
| 100 |
+
ExamAttemptCount int64 `json:"exam_attempt_count"`
|
| 101 |
+
ResultCount int64 `json:"result_count"`
|
| 102 |
+
PaidTransactionCount int64 `json:"paid_transaction_count"`
|
| 103 |
+
PaidRevenue float64 `json:"paid_revenue"`
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
type AdminProblemSetStatisticOverview struct {
|
| 107 |
+
TotalProblemSets int64 `json:"total_problemsets"`
|
| 108 |
+
TotalQuestions int64 `json:"total_questions"`
|
| 109 |
+
TotalExamAssignments int64 `json:"total_exam_assignments"`
|
| 110 |
+
AvgQuestionsPerProblemSet float64 `json:"avg_questions_per_problemset"`
|
| 111 |
+
AvgProblemSetsPerExam float64 `json:"avg_problemsets_per_exam"`
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
type AdminProblemSetStatisticDetail struct {
|
| 115 |
+
ProblemSetID string `json:"problemset_id"`
|
| 116 |
+
QuestionCount int64 `json:"question_count"`
|
| 117 |
+
ExamAssignmentCount int64 `json:"exam_assignment_count"`
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
type AdminQuestionStatisticOverview struct {
|
| 121 |
+
TotalQuestions int64 `json:"total_questions"`
|
| 122 |
+
TotalMultipleChoice int64 `json:"total_multiple_choice"`
|
| 123 |
+
TotalEssay int64 `json:"total_essay"`
|
| 124 |
+
AvgCorrectMark float64 `json:"avg_correct_mark"`
|
| 125 |
+
AvgIncorrectMark float64 `json:"avg_incorrect_mark"`
|
| 126 |
+
AvgNullMark float64 `json:"avg_null_mark"`
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
type AdminQuestionStatisticDetail struct {
|
| 130 |
+
QuestionID string `json:"question_id"`
|
| 131 |
+
ProblemSetID string `json:"problemset_id"`
|
| 132 |
+
QuestionType string `json:"question_type"`
|
| 133 |
+
CorrectMark float64 `json:"correct_mark"`
|
| 134 |
+
IncorrectMark float64 `json:"incorrect_mark"`
|
| 135 |
+
NullMark float64 `json:"null_mark"`
|
| 136 |
+
UsedInExamCount int64 `json:"used_in_exam_count"`
|
| 137 |
+
}
|
provider/controller_provider.go
CHANGED
|
@@ -1,58 +1,64 @@
|
|
| 1 |
-
package provider
|
| 2 |
-
|
| 3 |
-
import "abdanhafidz.com/go-boilerplate/controllers"
|
| 4 |
-
|
| 5 |
type ControllerProvider interface {
|
|
|
|
| 6 |
ProvideAdminEventController() controllers.AdminEventController
|
| 7 |
ProvideAdminExamController() controllers.AdminExamController
|
|
|
|
| 8 |
ProvideAdminProblemSetController() controllers.AdminProblemSetController
|
| 9 |
ProvideAcademyController() controllers.AcademyController
|
| 10 |
ProvideAcademyExamController() controllers.AcademyExamController
|
| 11 |
ProvideAccountDetailController() controllers.AccountDetailController
|
| 12 |
-
ProvideAuthenticationController() controllers.AuthenticationController
|
| 13 |
-
ProvideEmailVerificationController() controllers.EmailVerificationController
|
| 14 |
-
ProvideEventController() controllers.EventController
|
| 15 |
ProvideEventExamController() controllers.EventExamController
|
| 16 |
ProvideEventExamProctoringController() controllers.EventExamProctoringController
|
| 17 |
ProvidePaymentCallbackController() controllers.PaymentCallbackController
|
| 18 |
ProvideForgotPasswordController() controllers.ForgotPasswordController
|
| 19 |
ProvideOptionController() controllers.OptionController
|
| 20 |
ProvideRegionController() controllers.RegionController
|
| 21 |
-
ProvideUploadController() controllers.UploadController
|
| 22 |
-
ProvideUserController() controllers.UserController
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
type controllerProvider struct {
|
|
|
|
| 26 |
adminEventController controllers.AdminEventController
|
| 27 |
adminExamController controllers.AdminExamController
|
|
|
|
| 28 |
adminProblemSetController controllers.AdminProblemSetController
|
| 29 |
academyController controllers.AcademyController
|
| 30 |
-
academyExamController controllers.AcademyExamController
|
| 31 |
-
accountDetailController controllers.AccountDetailController
|
| 32 |
-
authenticationController controllers.AuthenticationController
|
| 33 |
-
emailVerificationController controllers.EmailVerificationController
|
| 34 |
-
eventController controllers.EventController
|
| 35 |
eventExamController controllers.EventExamController
|
| 36 |
eventExamProctoringController controllers.EventExamProctoringController
|
| 37 |
paymentCallbackController controllers.PaymentCallbackController
|
| 38 |
forgotPasswordController controllers.ForgotPasswordController
|
| 39 |
optionController controllers.OptionController
|
| 40 |
regionController controllers.RegionController
|
| 41 |
-
uploadController controllers.UploadController
|
| 42 |
-
userController controllers.UserController
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider {
|
| 46 |
-
|
| 47 |
adminEventController := controllers.NewAdminEventController(servicesProvider.ProvideAdminEventService())
|
| 48 |
adminExamController := controllers.NewAdminExamController(servicesProvider.ProvideAdminExamService())
|
|
|
|
|
|
|
| 49 |
adminProblemSetController := controllers.NewAdminProblemSetController(servicesProvider.ProvideProblemSetService())
|
| 50 |
academyController := controllers.NewAcademyController(servicesProvider.ProvideAcademyService())
|
| 51 |
-
academyExamController := controllers.NewAcademyExamController(servicesProvider.ProvideAcademyExamService())
|
| 52 |
-
accountDetailController := controllers.NewAccountDetailController(servicesProvider.ProvideAccountService())
|
| 53 |
-
authenticationController := controllers.NewAuthenticationController(servicesProvider.ProvideAccountService(), servicesProvider.ProvideExternalAuthService())
|
| 54 |
-
emailVerificationController := controllers.NewEmailVerificationController(servicesProvider.ProvideEmailVerificationService())
|
| 55 |
-
eventController := controllers.NewEventController(servicesProvider.ProvideEventService())
|
| 56 |
eventExamController := controllers.NewEventExamController(servicesProvider.ProvideEventExamService())
|
| 57 |
eventExamProctoringController := controllers.NewEventExamProctoringController(servicesProvider.ProvideEventExamProctoringService())
|
| 58 |
paymentCallbackController := controllers.NewPaymentCallbackController(
|
|
@@ -64,38 +70,48 @@ func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider
|
|
| 64 |
optionController := controllers.NewOptionController(servicesProvider.ProvideOptionService())
|
| 65 |
regionController := controllers.NewRegionController(servicesProvider.ProvideRegionService())
|
| 66 |
uploadController := controllers.NewUploadController(servicesProvider.ProvideUploadService())
|
| 67 |
-
userController := controllers.NewUserController(servicesProvider.ProvideAccountService())
|
| 68 |
return &controllerProvider{
|
|
|
|
| 69 |
adminEventController: adminEventController,
|
| 70 |
adminExamController: adminExamController,
|
|
|
|
| 71 |
adminProblemSetController: adminProblemSetController,
|
| 72 |
academyController: academyController,
|
| 73 |
-
academyExamController: academyExamController,
|
| 74 |
-
accountDetailController: accountDetailController,
|
| 75 |
-
authenticationController: authenticationController,
|
| 76 |
-
emailVerificationController: emailVerificationController,
|
| 77 |
-
eventController: eventController,
|
| 78 |
eventExamController: eventExamController,
|
| 79 |
eventExamProctoringController: eventExamProctoringController,
|
| 80 |
paymentCallbackController: paymentCallbackController,
|
| 81 |
forgotPasswordController: forgotPasswordController,
|
| 82 |
optionController: optionController,
|
| 83 |
regionController: regionController,
|
| 84 |
-
uploadController: uploadController,
|
| 85 |
-
userController: userController,
|
| 86 |
-
}
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
// --- Getter Methods ---
|
| 90 |
-
|
| 91 |
-
func (c *controllerProvider)
|
| 92 |
-
return c.
|
| 93 |
-
}
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
func (c *controllerProvider) ProvideAdminExamController() controllers.AdminExamController {
|
| 96 |
return c.adminExamController
|
| 97 |
}
|
| 98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
func (c *controllerProvider) ProvideAdminProblemSetController() controllers.AdminProblemSetController {
|
| 100 |
return c.adminProblemSetController
|
| 101 |
}
|
|
@@ -103,35 +119,35 @@ func (c *controllerProvider) ProvideAdminProblemSetController() controllers.Admi
|
|
| 103 |
func (c *controllerProvider) ProvideAcademyController() controllers.AcademyController {
|
| 104 |
return c.academyController
|
| 105 |
}
|
| 106 |
-
|
| 107 |
-
func (c *controllerProvider) ProvideAcademyExamController() controllers.AcademyExamController {
|
| 108 |
-
return c.academyExamController
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
func (c *controllerProvider) ProvideAccountDetailController() controllers.AccountDetailController {
|
| 112 |
-
return c.accountDetailController
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
func (c *controllerProvider) ProvideAuthenticationController() controllers.AuthenticationController {
|
| 116 |
-
return c.authenticationController
|
| 117 |
-
}
|
| 118 |
-
|
| 119 |
-
func (c *controllerProvider) ProvideEmailVerificationController() controllers.EmailVerificationController {
|
| 120 |
-
return c.emailVerificationController
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
func (c *controllerProvider) ProvideEventController() controllers.EventController {
|
| 124 |
-
return c.eventController
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
func (c *controllerProvider) ProvideEventExamController() controllers.EventExamController {
|
| 128 |
-
return c.eventExamController
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
func (c *controllerProvider) ProvideEventExamProctoringController() controllers.EventExamProctoringController {
|
| 132 |
-
return c.eventExamProctoringController
|
| 133 |
-
}
|
| 134 |
-
|
| 135 |
func (c *controllerProvider) ProvidePaymentCallbackController() controllers.PaymentCallbackController {
|
| 136 |
return c.paymentCallbackController
|
| 137 |
}
|
|
@@ -139,19 +155,19 @@ func (c *controllerProvider) ProvidePaymentCallbackController() controllers.Paym
|
|
| 139 |
func (c *controllerProvider) ProvideForgotPasswordController() controllers.ForgotPasswordController {
|
| 140 |
return c.forgotPasswordController
|
| 141 |
}
|
| 142 |
-
|
| 143 |
-
func (c *controllerProvider) ProvideOptionController() controllers.OptionController {
|
| 144 |
-
return c.optionController
|
| 145 |
-
}
|
| 146 |
-
|
| 147 |
-
func (c *controllerProvider) ProvideRegionController() controllers.RegionController {
|
| 148 |
-
return c.regionController
|
| 149 |
-
}
|
| 150 |
-
|
| 151 |
-
func (c *controllerProvider) ProvideUploadController() controllers.UploadController {
|
| 152 |
-
return c.uploadController
|
| 153 |
-
}
|
| 154 |
-
|
| 155 |
-
func (c *controllerProvider) ProvideUserController() controllers.UserController {
|
| 156 |
-
return c.userController
|
| 157 |
-
}
|
|
|
|
| 1 |
+
package provider
|
| 2 |
+
|
| 3 |
+
import "abdanhafidz.com/go-boilerplate/controllers"
|
| 4 |
+
|
| 5 |
type ControllerProvider interface {
|
| 6 |
+
ProvideAdminAcademyController() controllers.AdminAcademyController
|
| 7 |
ProvideAdminEventController() controllers.AdminEventController
|
| 8 |
ProvideAdminExamController() controllers.AdminExamController
|
| 9 |
+
ProvideAdminStatisticController() controllers.AdminStatisticController
|
| 10 |
ProvideAdminProblemSetController() controllers.AdminProblemSetController
|
| 11 |
ProvideAcademyController() controllers.AcademyController
|
| 12 |
ProvideAcademyExamController() controllers.AcademyExamController
|
| 13 |
ProvideAccountDetailController() controllers.AccountDetailController
|
| 14 |
+
ProvideAuthenticationController() controllers.AuthenticationController
|
| 15 |
+
ProvideEmailVerificationController() controllers.EmailVerificationController
|
| 16 |
+
ProvideEventController() controllers.EventController
|
| 17 |
ProvideEventExamController() controllers.EventExamController
|
| 18 |
ProvideEventExamProctoringController() controllers.EventExamProctoringController
|
| 19 |
ProvidePaymentCallbackController() controllers.PaymentCallbackController
|
| 20 |
ProvideForgotPasswordController() controllers.ForgotPasswordController
|
| 21 |
ProvideOptionController() controllers.OptionController
|
| 22 |
ProvideRegionController() controllers.RegionController
|
| 23 |
+
ProvideUploadController() controllers.UploadController
|
| 24 |
+
ProvideUserController() controllers.UserController
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
type controllerProvider struct {
|
| 28 |
+
adminAcademyController controllers.AdminAcademyController
|
| 29 |
adminEventController controllers.AdminEventController
|
| 30 |
adminExamController controllers.AdminExamController
|
| 31 |
+
adminStatisticController controllers.AdminStatisticController
|
| 32 |
adminProblemSetController controllers.AdminProblemSetController
|
| 33 |
academyController controllers.AcademyController
|
| 34 |
+
academyExamController controllers.AcademyExamController
|
| 35 |
+
accountDetailController controllers.AccountDetailController
|
| 36 |
+
authenticationController controllers.AuthenticationController
|
| 37 |
+
emailVerificationController controllers.EmailVerificationController
|
| 38 |
+
eventController controllers.EventController
|
| 39 |
eventExamController controllers.EventExamController
|
| 40 |
eventExamProctoringController controllers.EventExamProctoringController
|
| 41 |
paymentCallbackController controllers.PaymentCallbackController
|
| 42 |
forgotPasswordController controllers.ForgotPasswordController
|
| 43 |
optionController controllers.OptionController
|
| 44 |
regionController controllers.RegionController
|
| 45 |
+
uploadController controllers.UploadController
|
| 46 |
+
userController controllers.UserController
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider {
|
| 50 |
+
|
| 51 |
adminEventController := controllers.NewAdminEventController(servicesProvider.ProvideAdminEventService())
|
| 52 |
adminExamController := controllers.NewAdminExamController(servicesProvider.ProvideAdminExamService())
|
| 53 |
+
adminStatisticController := controllers.NewAdminStatisticController(servicesProvider.ProvideAdminStatisticService())
|
| 54 |
+
adminAcademyController := controllers.NewAdminAcademyController(servicesProvider.ProvideAdminAcademyService())
|
| 55 |
adminProblemSetController := controllers.NewAdminProblemSetController(servicesProvider.ProvideProblemSetService())
|
| 56 |
academyController := controllers.NewAcademyController(servicesProvider.ProvideAcademyService())
|
| 57 |
+
academyExamController := controllers.NewAcademyExamController(servicesProvider.ProvideAcademyExamService())
|
| 58 |
+
accountDetailController := controllers.NewAccountDetailController(servicesProvider.ProvideAccountService())
|
| 59 |
+
authenticationController := controllers.NewAuthenticationController(servicesProvider.ProvideAccountService(), servicesProvider.ProvideExternalAuthService())
|
| 60 |
+
emailVerificationController := controllers.NewEmailVerificationController(servicesProvider.ProvideEmailVerificationService())
|
| 61 |
+
eventController := controllers.NewEventController(servicesProvider.ProvideEventService())
|
| 62 |
eventExamController := controllers.NewEventExamController(servicesProvider.ProvideEventExamService())
|
| 63 |
eventExamProctoringController := controllers.NewEventExamProctoringController(servicesProvider.ProvideEventExamProctoringService())
|
| 64 |
paymentCallbackController := controllers.NewPaymentCallbackController(
|
|
|
|
| 70 |
optionController := controllers.NewOptionController(servicesProvider.ProvideOptionService())
|
| 71 |
regionController := controllers.NewRegionController(servicesProvider.ProvideRegionService())
|
| 72 |
uploadController := controllers.NewUploadController(servicesProvider.ProvideUploadService())
|
| 73 |
+
userController := controllers.NewUserController(servicesProvider.ProvideAccountService())
|
| 74 |
return &controllerProvider{
|
| 75 |
+
adminAcademyController: adminAcademyController,
|
| 76 |
adminEventController: adminEventController,
|
| 77 |
adminExamController: adminExamController,
|
| 78 |
+
adminStatisticController: adminStatisticController,
|
| 79 |
adminProblemSetController: adminProblemSetController,
|
| 80 |
academyController: academyController,
|
| 81 |
+
academyExamController: academyExamController,
|
| 82 |
+
accountDetailController: accountDetailController,
|
| 83 |
+
authenticationController: authenticationController,
|
| 84 |
+
emailVerificationController: emailVerificationController,
|
| 85 |
+
eventController: eventController,
|
| 86 |
eventExamController: eventExamController,
|
| 87 |
eventExamProctoringController: eventExamProctoringController,
|
| 88 |
paymentCallbackController: paymentCallbackController,
|
| 89 |
forgotPasswordController: forgotPasswordController,
|
| 90 |
optionController: optionController,
|
| 91 |
regionController: regionController,
|
| 92 |
+
uploadController: uploadController,
|
| 93 |
+
userController: userController,
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
// --- Getter Methods ---
|
| 98 |
+
|
| 99 |
+
func (c *controllerProvider) ProvideAdminAcademyController() controllers.AdminAcademyController {
|
| 100 |
+
return c.adminAcademyController
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
func (c *controllerProvider) ProvideAdminEventController() controllers.AdminEventController {
|
| 104 |
+
return c.adminEventController
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
func (c *controllerProvider) ProvideAdminExamController() controllers.AdminExamController {
|
| 108 |
return c.adminExamController
|
| 109 |
}
|
| 110 |
|
| 111 |
+
func (c *controllerProvider) ProvideAdminStatisticController() controllers.AdminStatisticController {
|
| 112 |
+
return c.adminStatisticController
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
func (c *controllerProvider) ProvideAdminProblemSetController() controllers.AdminProblemSetController {
|
| 116 |
return c.adminProblemSetController
|
| 117 |
}
|
|
|
|
| 119 |
func (c *controllerProvider) ProvideAcademyController() controllers.AcademyController {
|
| 120 |
return c.academyController
|
| 121 |
}
|
| 122 |
+
|
| 123 |
+
func (c *controllerProvider) ProvideAcademyExamController() controllers.AcademyExamController {
|
| 124 |
+
return c.academyExamController
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
func (c *controllerProvider) ProvideAccountDetailController() controllers.AccountDetailController {
|
| 128 |
+
return c.accountDetailController
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
func (c *controllerProvider) ProvideAuthenticationController() controllers.AuthenticationController {
|
| 132 |
+
return c.authenticationController
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
func (c *controllerProvider) ProvideEmailVerificationController() controllers.EmailVerificationController {
|
| 136 |
+
return c.emailVerificationController
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
func (c *controllerProvider) ProvideEventController() controllers.EventController {
|
| 140 |
+
return c.eventController
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
func (c *controllerProvider) ProvideEventExamController() controllers.EventExamController {
|
| 144 |
+
return c.eventExamController
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
func (c *controllerProvider) ProvideEventExamProctoringController() controllers.EventExamProctoringController {
|
| 148 |
+
return c.eventExamProctoringController
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
func (c *controllerProvider) ProvidePaymentCallbackController() controllers.PaymentCallbackController {
|
| 152 |
return c.paymentCallbackController
|
| 153 |
}
|
|
|
|
| 155 |
func (c *controllerProvider) ProvideForgotPasswordController() controllers.ForgotPasswordController {
|
| 156 |
return c.forgotPasswordController
|
| 157 |
}
|
| 158 |
+
|
| 159 |
+
func (c *controllerProvider) ProvideOptionController() controllers.OptionController {
|
| 160 |
+
return c.optionController
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
func (c *controllerProvider) ProvideRegionController() controllers.RegionController {
|
| 164 |
+
return c.regionController
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
func (c *controllerProvider) ProvideUploadController() controllers.UploadController {
|
| 168 |
+
return c.uploadController
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
func (c *controllerProvider) ProvideUserController() controllers.UserController {
|
| 172 |
+
return c.userController
|
| 173 |
+
}
|
provider/repositories_provider.go
CHANGED
|
@@ -1,250 +1,266 @@
|
|
| 1 |
-
package provider
|
| 2 |
-
|
| 3 |
-
import "abdanhafidz.com/go-boilerplate/repositories"
|
| 4 |
-
|
| 5 |
-
type RepositoriesProvider interface {
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
}
|
| 143 |
-
|
| 144 |
-
func (r *repositoriesProvider)
|
| 145 |
-
return r.
|
| 146 |
-
}
|
| 147 |
-
|
| 148 |
-
func (r *repositoriesProvider)
|
| 149 |
-
return r.
|
| 150 |
-
}
|
| 151 |
-
|
| 152 |
-
func (r *repositoriesProvider)
|
| 153 |
-
return r.
|
| 154 |
-
}
|
| 155 |
-
|
| 156 |
-
func (r *repositoriesProvider)
|
| 157 |
-
return r.
|
| 158 |
-
}
|
| 159 |
-
|
| 160 |
-
func (r *repositoriesProvider)
|
| 161 |
-
return r.
|
| 162 |
-
}
|
| 163 |
-
|
| 164 |
-
func (r *repositoriesProvider)
|
| 165 |
-
return r.
|
| 166 |
-
}
|
| 167 |
-
|
| 168 |
-
func (r *repositoriesProvider)
|
| 169 |
-
return r.
|
| 170 |
-
}
|
| 171 |
-
|
| 172 |
-
func (r *repositoriesProvider)
|
| 173 |
-
return r.
|
| 174 |
-
}
|
| 175 |
-
|
| 176 |
-
func (r *repositoriesProvider)
|
| 177 |
-
return r.
|
| 178 |
-
}
|
| 179 |
-
|
| 180 |
-
func (r *repositoriesProvider)
|
| 181 |
-
return r.
|
| 182 |
-
}
|
| 183 |
-
|
| 184 |
-
func (r *repositoriesProvider)
|
| 185 |
-
return r.
|
| 186 |
-
}
|
| 187 |
-
|
| 188 |
-
func (r *repositoriesProvider)
|
| 189 |
-
return r.
|
| 190 |
-
}
|
| 191 |
-
|
| 192 |
-
func (r *repositoriesProvider)
|
| 193 |
-
return r.
|
| 194 |
-
}
|
| 195 |
-
|
| 196 |
-
func (r *repositoriesProvider)
|
| 197 |
-
return r.
|
| 198 |
-
}
|
| 199 |
-
|
| 200 |
-
func (r *repositoriesProvider)
|
| 201 |
-
return r.
|
| 202 |
-
}
|
| 203 |
-
|
| 204 |
-
func (r *repositoriesProvider)
|
| 205 |
-
return r.
|
| 206 |
-
}
|
| 207 |
-
|
| 208 |
-
func (r *repositoriesProvider)
|
| 209 |
-
return r.
|
| 210 |
-
}
|
| 211 |
-
|
| 212 |
-
func (r *repositoriesProvider)
|
| 213 |
-
return r.
|
| 214 |
-
}
|
| 215 |
-
|
| 216 |
-
func (r *repositoriesProvider)
|
| 217 |
-
return r.
|
| 218 |
-
}
|
| 219 |
-
|
| 220 |
-
func (r *repositoriesProvider)
|
| 221 |
-
return r.
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
func (r *repositoriesProvider)
|
| 225 |
-
return r.
|
| 226 |
-
}
|
| 227 |
-
|
| 228 |
-
func (r *repositoriesProvider)
|
| 229 |
-
return r.
|
| 230 |
-
}
|
| 231 |
-
|
| 232 |
-
func (r *repositoriesProvider)
|
| 233 |
-
return r.
|
| 234 |
-
}
|
| 235 |
-
|
| 236 |
-
func (r *repositoriesProvider)
|
| 237 |
-
return r.
|
| 238 |
-
}
|
| 239 |
-
|
| 240 |
-
func (r *repositoriesProvider)
|
| 241 |
-
return r.
|
| 242 |
-
}
|
| 243 |
-
|
| 244 |
-
func (r *repositoriesProvider)
|
| 245 |
-
return r.
|
| 246 |
-
}
|
| 247 |
-
|
| 248 |
-
func (r *repositoriesProvider)
|
| 249 |
-
return r.
|
| 250 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package provider
|
| 2 |
+
|
| 3 |
+
import "abdanhafidz.com/go-boilerplate/repositories"
|
| 4 |
+
|
| 5 |
+
type RepositoriesProvider interface {
|
| 6 |
+
ProvideAdminAcademyRepository() repositories.AdminAcademyRepository
|
| 7 |
+
ProvideAdminEventRepository() repositories.AdminEventRepository
|
| 8 |
+
ProvideAdminExamRepository() repositories.AdminExamRepository
|
| 9 |
+
ProvideAdminStatisticRepository() repositories.AdminStatisticRepository
|
| 10 |
+
ProvideAcademyPaymentRepository() repositories.AcademyPaymentRepository
|
| 11 |
+
ProvideAcademyRepository() repositories.AcademyRepository
|
| 12 |
+
ProvideAcademyResultRepository() repositories.AcademyResultRepository
|
| 13 |
+
ProvideAccountDetailRepository() repositories.AccountDetailRepository
|
| 14 |
+
ProvideAccountRepository() repositories.AccountRepository
|
| 15 |
+
ProvideEmailVerificationRepository() repositories.EmailVerificationRepository
|
| 16 |
+
ProvideEventAssignRepository() repositories.EventAssignRepository
|
| 17 |
+
ProvideEventPaymentRepository() repositories.EventPaymentRepository
|
| 18 |
+
ProvideEventsRepository() repositories.EventsRepository
|
| 19 |
+
ProvideAcademyExamAnswerRepository() repositories.AcademyExamAnswerRepository
|
| 20 |
+
ProvideAcademyExamAssignRepository() repositories.AcademyExamAssignRepository
|
| 21 |
+
ProvideAcademyExamAttemptRepository() repositories.AcademyExamAttemptRepository
|
| 22 |
+
ProvideEventExamAnswerRepository() repositories.EventExamAnswerRepository
|
| 23 |
+
ProvideEventExamAssignRepository() repositories.EventExamAssignRepository
|
| 24 |
+
ProvideEventExamAttemptRepository() repositories.EventExamAttemptRepository
|
| 25 |
+
ProvideEventExamProctoringRepository() repositories.EventExamProctoringRepository
|
| 26 |
+
ProvideExamRepository() repositories.ExamRepository
|
| 27 |
+
ProvideExternalAuthRepository() repositories.ExternalAuthRepository
|
| 28 |
+
ProvideFCMRepository() repositories.FCMRepository
|
| 29 |
+
ProvideFileRepository() repositories.FileRepository
|
| 30 |
+
ProvideForgotPasswordRepository() repositories.ForgotPasswordRepository
|
| 31 |
+
ProvideOptionRepository() repositories.OptionRepository
|
| 32 |
+
ProvideProblemSetExamAssignRepository() repositories.ProblemSetExamAssignRepository
|
| 33 |
+
ProvideProblemSetRepository() repositories.ProblemSetRepository
|
| 34 |
+
ProvideQuestionsRepository() repositories.QuestionsRepository
|
| 35 |
+
ProvideRegionRepository() repositories.RegionRepository
|
| 36 |
+
ProvideResultRepository() repositories.ResultRepository
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
type repositoriesProvider struct {
|
| 40 |
+
adminAcademyRepository repositories.AdminAcademyRepository
|
| 41 |
+
adminEventRepository repositories.AdminEventRepository
|
| 42 |
+
adminExamRepository repositories.AdminExamRepository
|
| 43 |
+
adminStatisticRepository repositories.AdminStatisticRepository
|
| 44 |
+
academyPaymentRepository repositories.AcademyPaymentRepository
|
| 45 |
+
academyRepository repositories.AcademyRepository
|
| 46 |
+
academyResultRepository repositories.AcademyResultRepository
|
| 47 |
+
accountDetailRepository repositories.AccountDetailRepository
|
| 48 |
+
accountRepository repositories.AccountRepository
|
| 49 |
+
emailVerificationRepository repositories.EmailVerificationRepository
|
| 50 |
+
eventAssignRepository repositories.EventAssignRepository
|
| 51 |
+
eventPaymentRepository repositories.EventPaymentRepository
|
| 52 |
+
eventsRepository repositories.EventsRepository
|
| 53 |
+
academyExamAnswerRepository repositories.AcademyExamAnswerRepository
|
| 54 |
+
academyExamAssignRepository repositories.AcademyExamAssignRepository
|
| 55 |
+
academyExamAttemptRepository repositories.AcademyExamAttemptRepository
|
| 56 |
+
eventExamAnswerRepository repositories.EventExamAnswerRepository
|
| 57 |
+
eventExamAssignRepository repositories.EventExamAssignRepository
|
| 58 |
+
eventExamAttemptRepository repositories.EventExamAttemptRepository
|
| 59 |
+
eventExamProctoringRepository repositories.EventExamProctoringRepository
|
| 60 |
+
examRepository repositories.ExamRepository
|
| 61 |
+
externalAuthRepository repositories.ExternalAuthRepository
|
| 62 |
+
fCMRepository repositories.FCMRepository
|
| 63 |
+
fileRepository repositories.FileRepository
|
| 64 |
+
forgotPasswordRepository repositories.ForgotPasswordRepository
|
| 65 |
+
optionRepository repositories.OptionRepository
|
| 66 |
+
problemSetExamAssignRepository repositories.ProblemSetExamAssignRepository
|
| 67 |
+
problemSetRepository repositories.ProblemSetRepository
|
| 68 |
+
questionsRepository repositories.QuestionsRepository
|
| 69 |
+
regionRepository repositories.RegionRepository
|
| 70 |
+
resultRepository repositories.ResultRepository
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
func NewRepositoriesProvider(cfg ConfigProvider) RepositoriesProvider {
|
| 74 |
+
dbConfig := cfg.ProvideDatabaseConfig()
|
| 75 |
+
db := dbConfig.GetInstance()
|
| 76 |
+
|
| 77 |
+
adminEventRepository := repositories.NewAdminEventRepository(db)
|
| 78 |
+
adminExamRepository := repositories.NewAdminExamRepository(db)
|
| 79 |
+
adminStatisticRepository := repositories.NewAdminStatisticRepository(db)
|
| 80 |
+
adminAcademyRepository := repositories.NewAdminAcademyRepository(db)
|
| 81 |
+
academyPaymentRepository := repositories.NewAcaddemyPaymentRepository(db)
|
| 82 |
+
academyRepository := repositories.NewAcademyRepository(db)
|
| 83 |
+
academyResultRepository := repositories.NewAcademyResultRepository(db)
|
| 84 |
+
accountDetailRepository := repositories.NewAccountDetailRepository(db)
|
| 85 |
+
accountRepository := repositories.NewAccountRepository(db)
|
| 86 |
+
emailVerificationRepository := repositories.NewEmailVerificationRepository(db)
|
| 87 |
+
eventAssignRepository := repositories.NewEventAssignRepository(db)
|
| 88 |
+
eventPaymentRepository := repositories.NewEventPaymentRepository(db)
|
| 89 |
+
eventsRepository := repositories.NewEventsRepository(db)
|
| 90 |
+
academyExamAnswerRepository := repositories.NewAcademyExamAnswerRepository(db)
|
| 91 |
+
academyExamAssignRepository := repositories.NewAcademyExamAssignRepository(db)
|
| 92 |
+
academyExamAttemptRepository := repositories.NewAcademyExamAttemptRepository(db)
|
| 93 |
+
eventExamAnswerRepository := repositories.NewEventExamAnswerRepository(db)
|
| 94 |
+
eventExamAssignRepository := repositories.NewEventExamAssignRepository(db)
|
| 95 |
+
eventExamAttemptRepository := repositories.NewEventExamAttemptRepository(db)
|
| 96 |
+
eventExamProctoringRepository := repositories.NewEventExamProctoringRepository(db)
|
| 97 |
+
examRepository := repositories.NewExamRepository(db)
|
| 98 |
+
externalAuthRepository := repositories.NewExternalAuthRepository(db)
|
| 99 |
+
fCMRepository := repositories.NewFCMRepository(db)
|
| 100 |
+
fileRepository := repositories.NewFileRepository(db)
|
| 101 |
+
forgotPasswordRepository := repositories.NewForgotPasswordRepository(db)
|
| 102 |
+
optionRepository := repositories.NewOptionRepository(db)
|
| 103 |
+
problemSetExamAssignRepository := repositories.NewProblemSetExamAssignRepository(db)
|
| 104 |
+
problemSetRepository := repositories.NewProblemSetRepository(db)
|
| 105 |
+
questionsRepository := repositories.NewQuestionsRepository(db)
|
| 106 |
+
regionRepository := repositories.NewRegionRepository(db)
|
| 107 |
+
resultRepository := repositories.NewResultRepository(db)
|
| 108 |
+
|
| 109 |
+
return &repositoriesProvider{
|
| 110 |
+
adminAcademyRepository: adminAcademyRepository,
|
| 111 |
+
adminEventRepository: adminEventRepository,
|
| 112 |
+
adminExamRepository: adminExamRepository,
|
| 113 |
+
adminStatisticRepository: adminStatisticRepository,
|
| 114 |
+
academyPaymentRepository: academyPaymentRepository,
|
| 115 |
+
academyRepository: academyRepository,
|
| 116 |
+
academyResultRepository: academyResultRepository,
|
| 117 |
+
accountDetailRepository: accountDetailRepository,
|
| 118 |
+
accountRepository: accountRepository,
|
| 119 |
+
emailVerificationRepository: emailVerificationRepository,
|
| 120 |
+
eventAssignRepository: eventAssignRepository,
|
| 121 |
+
eventPaymentRepository: eventPaymentRepository,
|
| 122 |
+
eventsRepository: eventsRepository,
|
| 123 |
+
academyExamAnswerRepository: academyExamAnswerRepository,
|
| 124 |
+
academyExamAssignRepository: academyExamAssignRepository,
|
| 125 |
+
academyExamAttemptRepository: academyExamAttemptRepository,
|
| 126 |
+
eventExamAnswerRepository: eventExamAnswerRepository,
|
| 127 |
+
eventExamAssignRepository: eventExamAssignRepository,
|
| 128 |
+
eventExamAttemptRepository: eventExamAttemptRepository,
|
| 129 |
+
eventExamProctoringRepository: eventExamProctoringRepository,
|
| 130 |
+
examRepository: examRepository,
|
| 131 |
+
externalAuthRepository: externalAuthRepository,
|
| 132 |
+
fCMRepository: fCMRepository,
|
| 133 |
+
fileRepository: fileRepository,
|
| 134 |
+
forgotPasswordRepository: forgotPasswordRepository,
|
| 135 |
+
optionRepository: optionRepository,
|
| 136 |
+
problemSetExamAssignRepository: problemSetExamAssignRepository,
|
| 137 |
+
problemSetRepository: problemSetRepository,
|
| 138 |
+
questionsRepository: questionsRepository,
|
| 139 |
+
regionRepository: regionRepository,
|
| 140 |
+
resultRepository: resultRepository,
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
func (r *repositoriesProvider) ProvideAdminAcademyRepository() repositories.AdminAcademyRepository {
|
| 145 |
+
return r.adminAcademyRepository
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
func (r *repositoriesProvider) ProvideAdminEventRepository() repositories.AdminEventRepository {
|
| 149 |
+
return r.adminEventRepository
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
func (r *repositoriesProvider) ProvideAdminExamRepository() repositories.AdminExamRepository {
|
| 153 |
+
return r.adminExamRepository
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
func (r *repositoriesProvider) ProvideAdminStatisticRepository() repositories.AdminStatisticRepository {
|
| 157 |
+
return r.adminStatisticRepository
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
func (r *repositoriesProvider) ProvideAcademyPaymentRepository() repositories.AcademyPaymentRepository {
|
| 161 |
+
return r.academyPaymentRepository
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
func (r *repositoriesProvider) ProvideAcademyRepository() repositories.AcademyRepository {
|
| 165 |
+
return r.academyRepository
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
func (r *repositoriesProvider) ProvideAcademyResultRepository() repositories.AcademyResultRepository {
|
| 169 |
+
return r.academyResultRepository
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
func (r *repositoriesProvider) ProvideAccountDetailRepository() repositories.AccountDetailRepository {
|
| 173 |
+
return r.accountDetailRepository
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
func (r *repositoriesProvider) ProvideAccountRepository() repositories.AccountRepository {
|
| 177 |
+
return r.accountRepository
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
func (r *repositoriesProvider) ProvideEmailVerificationRepository() repositories.EmailVerificationRepository {
|
| 181 |
+
return r.emailVerificationRepository
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
func (r *repositoriesProvider) ProvideEventAssignRepository() repositories.EventAssignRepository {
|
| 185 |
+
return r.eventAssignRepository
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
func (r *repositoriesProvider) ProvideEventPaymentRepository() repositories.EventPaymentRepository {
|
| 189 |
+
return r.eventPaymentRepository
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
func (r *repositoriesProvider) ProvideEventsRepository() repositories.EventsRepository {
|
| 193 |
+
return r.eventsRepository
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
func (r *repositoriesProvider) ProvideAcademyExamAnswerRepository() repositories.AcademyExamAnswerRepository {
|
| 197 |
+
return r.academyExamAnswerRepository
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
func (r *repositoriesProvider) ProvideAcademyExamAssignRepository() repositories.AcademyExamAssignRepository {
|
| 201 |
+
return r.academyExamAssignRepository
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
func (r *repositoriesProvider) ProvideAcademyExamAttemptRepository() repositories.AcademyExamAttemptRepository {
|
| 205 |
+
return r.academyExamAttemptRepository
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
func (r *repositoriesProvider) ProvideEventExamAnswerRepository() repositories.EventExamAnswerRepository {
|
| 209 |
+
return r.eventExamAnswerRepository
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
func (r *repositoriesProvider) ProvideEventExamAssignRepository() repositories.EventExamAssignRepository {
|
| 213 |
+
return r.eventExamAssignRepository
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
func (r *repositoriesProvider) ProvideEventExamAttemptRepository() repositories.EventExamAttemptRepository {
|
| 217 |
+
return r.eventExamAttemptRepository
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
func (r *repositoriesProvider) ProvideEventExamProctoringRepository() repositories.EventExamProctoringRepository {
|
| 221 |
+
return r.eventExamProctoringRepository
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
func (r *repositoriesProvider) ProvideExamRepository() repositories.ExamRepository {
|
| 225 |
+
return r.examRepository
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
func (r *repositoriesProvider) ProvideExternalAuthRepository() repositories.ExternalAuthRepository {
|
| 229 |
+
return r.externalAuthRepository
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
func (r *repositoriesProvider) ProvideFCMRepository() repositories.FCMRepository {
|
| 233 |
+
return r.fCMRepository
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
func (r *repositoriesProvider) ProvideFileRepository() repositories.FileRepository {
|
| 237 |
+
return r.fileRepository
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
func (r *repositoriesProvider) ProvideForgotPasswordRepository() repositories.ForgotPasswordRepository {
|
| 241 |
+
return r.forgotPasswordRepository
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
func (r *repositoriesProvider) ProvideOptionRepository() repositories.OptionRepository {
|
| 245 |
+
return r.optionRepository
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
func (r *repositoriesProvider) ProvideProblemSetExamAssignRepository() repositories.ProblemSetExamAssignRepository {
|
| 249 |
+
return r.problemSetExamAssignRepository
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
func (r *repositoriesProvider) ProvideProblemSetRepository() repositories.ProblemSetRepository {
|
| 253 |
+
return r.problemSetRepository
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
func (r *repositoriesProvider) ProvideQuestionsRepository() repositories.QuestionsRepository {
|
| 257 |
+
return r.questionsRepository
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
func (r *repositoriesProvider) ProvideRegionRepository() repositories.RegionRepository {
|
| 261 |
+
return r.regionRepository
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
func (r *repositoriesProvider) ProvideResultRepository() repositories.ResultRepository {
|
| 265 |
+
return r.resultRepository
|
| 266 |
+
}
|
provider/services_provider.go
CHANGED
|
@@ -1,161 +1,177 @@
|
|
| 1 |
-
package provider
|
| 2 |
-
|
| 3 |
-
import (
|
| 4 |
-
"abdanhafidz.com/go-boilerplate/config"
|
| 5 |
-
"abdanhafidz.com/go-boilerplate/services"
|
| 6 |
-
)
|
| 7 |
-
|
| 8 |
-
type ServicesProvider interface {
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
| 24 |
ProvideEventExamService() services.EventExamService
|
| 25 |
ProvideEventExamProctoringService() services.EventExamProctoringService
|
| 26 |
}
|
| 27 |
-
|
| 28 |
-
type servicesProvider struct {
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
| 44 |
eventExamService services.EventExamService
|
| 45 |
eventExamProctoringService services.EventExamProctoringService
|
| 46 |
}
|
| 47 |
-
|
| 48 |
-
func NewServicesProvider(repoProvider RepositoriesProvider, configProvider ConfigProvider) ServicesProvider {
|
| 49 |
-
regionService := services.NewRegionService(repoProvider.ProvideRegionRepository())
|
| 50 |
-
jWTService := services.NewJWTService(configProvider.ProvideJWTConfig().GetSecretKey())
|
| 51 |
-
paymentService := services.NewPaymentService(configProvider.ProvideXenditConfig().GetClient(), repoProvider.ProvideEventPaymentRepository(), repoProvider.ProvideAcademyPaymentRepository(), repoProvider.ProvideEventAssignRepository(), repoProvider.ProvideAcademyRepository())
|
| 52 |
-
academyService := services.NewAcademyService(paymentService, repoProvider.ProvideAcademyRepository())
|
| 53 |
-
storageService := services.NewSupabaseStorageService(configProvider.ProvideSupabaseConfig().GetURL(), configProvider.ProvideSupabaseConfig().GetServiceKey(), configProvider.ProvideSupabaseConfig().GetBucketName())
|
| 54 |
-
uploadService := services.NewUploadService(
|
| 55 |
-
storageService,
|
| 56 |
-
repoProvider.ProvideFileRepository(),
|
| 57 |
-
repoProvider.ProvideAccountRepository(),
|
| 58 |
-
config.NewUploadConfig(),
|
| 59 |
-
)
|
| 60 |
-
problemSetService := services.NewProblemSetService(repoProvider.ProvideProblemSetRepository(), repoProvider.ProvideQuestionsRepository(), repoProvider.ProvideProblemSetExamAssignRepository())
|
| 61 |
-
optionService := services.NewOptionService(repoProvider.ProvideOptionRepository())
|
| 62 |
-
accountService := services.NewAccountService(jWTService, repoProvider.ProvideAccountRepository(), repoProvider.ProvideAccountDetailRepository())
|
| 63 |
-
forgotPasswordService := services.NewForgotPasswordService(jWTService, repoProvider.ProvideAccountRepository(), repoProvider.ProvideForgotPasswordRepository())
|
| 64 |
-
eventService := services.NewEventService(paymentService, repoProvider.ProvideEventsRepository(), repoProvider.ProvideEventAssignRepository())
|
| 65 |
-
academyExamService := services.NewAcademyExamService(academyService, problemSetService, repoProvider.ProvideExamRepository(), repoProvider.ProvideAcademyExamAttemptRepository(), repoProvider.ProvideAcademyExamAssignRepository(), repoProvider.ProvideAcademyExamAnswerRepository(), repoProvider.ProvideAcademyResultRepository())
|
| 66 |
-
emailVerificationService := services.NewEmailVerificationService(accountService, repoProvider.ProvideEmailVerificationRepository())
|
| 67 |
-
externalAuthService := services.NewExternalAuthService(jWTService, accountService, repoProvider.ProvideExternalAuthRepository())
|
| 68 |
eventExamService := services.NewEventExamService(eventService, problemSetService, repoProvider.ProvideProblemSetExamAssignRepository(), repoProvider.ProvideExamRepository(), repoProvider.ProvideEventExamAttemptRepository(), repoProvider.ProvideEventExamAssignRepository(), repoProvider.ProvideEventExamAnswerRepository(), repoProvider.ProvideResultRepository())
|
| 69 |
eventExamProctoringService := services.NewEventExamProctoringService(eventExamService, uploadService, repoProvider.ProvideEventExamProctoringRepository())
|
| 70 |
|
| 71 |
adminEventService := services.NewAdminEventService(eventService, repoProvider.ProvideAdminEventRepository(), repoProvider.ProvideEventAssignRepository(), repoProvider.ProvideEventExamAssignRepository(), repoProvider.ProvideResultRepository())
|
| 72 |
adminExamService := services.NewAdminExamService(repoProvider.ProvideAdminExamRepository())
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
eventExamService: eventExamService,
|
| 91 |
eventExamProctoringService: eventExamProctoringService,
|
| 92 |
}
|
| 93 |
}
|
| 94 |
-
|
| 95 |
-
func (s *servicesProvider)
|
| 96 |
-
return s.
|
| 97 |
-
}
|
| 98 |
-
|
| 99 |
-
func (s *servicesProvider)
|
| 100 |
-
return s.
|
| 101 |
-
}
|
| 102 |
-
|
| 103 |
-
func (s *servicesProvider)
|
| 104 |
-
return s.
|
| 105 |
-
}
|
| 106 |
-
|
| 107 |
-
func (s *servicesProvider)
|
| 108 |
-
return s.
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
func (s *servicesProvider)
|
| 112 |
-
return s.
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
func (s *servicesProvider)
|
| 116 |
-
return s.
|
| 117 |
-
}
|
| 118 |
-
|
| 119 |
-
func (s *servicesProvider)
|
| 120 |
-
return s.
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
func (s *servicesProvider)
|
| 124 |
-
return s.
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
func (s *servicesProvider)
|
| 128 |
-
return s.
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
func (s *servicesProvider)
|
| 132 |
-
return s.
|
| 133 |
-
}
|
| 134 |
-
|
| 135 |
-
func (s *servicesProvider)
|
| 136 |
-
return s.
|
| 137 |
-
}
|
| 138 |
-
|
| 139 |
-
func (s *servicesProvider)
|
| 140 |
-
return s.
|
| 141 |
-
}
|
| 142 |
-
|
| 143 |
-
func (s *servicesProvider)
|
| 144 |
-
return s.
|
| 145 |
-
}
|
| 146 |
-
|
| 147 |
-
func (s *servicesProvider)
|
| 148 |
-
return s.
|
| 149 |
-
}
|
| 150 |
-
|
| 151 |
-
func (s *servicesProvider)
|
| 152 |
-
return s.
|
| 153 |
-
}
|
| 154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
func (s *servicesProvider) ProvideEventExamService() services.EventExamService {
|
| 156 |
return s.eventExamService
|
| 157 |
}
|
| 158 |
-
|
| 159 |
-
func (s *servicesProvider) ProvideEventExamProctoringService() services.EventExamProctoringService {
|
| 160 |
-
return s.eventExamProctoringService
|
| 161 |
-
}
|
|
|
|
| 1 |
+
package provider
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"abdanhafidz.com/go-boilerplate/config"
|
| 5 |
+
"abdanhafidz.com/go-boilerplate/services"
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
type ServicesProvider interface {
|
| 9 |
+
ProvideAdminAcademyService() services.AdminAcademyService
|
| 10 |
+
ProvideAdminEventService() services.AdminEventService
|
| 11 |
+
ProvideAdminExamService() services.AdminExamService
|
| 12 |
+
ProvideAdminStatisticService() services.AdminStatisticService
|
| 13 |
+
ProvideRegionService() services.RegionService
|
| 14 |
+
ProvideJWTService() services.JWTService
|
| 15 |
+
ProvideAcademyService() services.AcademyService
|
| 16 |
+
ProvidePaymentService() services.PaymentService
|
| 17 |
+
ProvideUploadService() services.UploadService
|
| 18 |
+
ProvideProblemSetService() services.ProblemSetService
|
| 19 |
+
ProvideOptionService() services.OptionService
|
| 20 |
+
ProvideAccountService() services.AccountService
|
| 21 |
+
ProvideForgotPasswordService() services.ForgotPasswordService
|
| 22 |
+
ProvideEventService() services.EventService
|
| 23 |
+
ProvideAcademyExamService() services.AcademyExamService
|
| 24 |
+
ProvideEmailVerificationService() services.EmailVerificationService
|
| 25 |
+
ProvideExternalAuthService() services.ExternalAuthService
|
| 26 |
ProvideEventExamService() services.EventExamService
|
| 27 |
ProvideEventExamProctoringService() services.EventExamProctoringService
|
| 28 |
}
|
| 29 |
+
|
| 30 |
+
type servicesProvider struct {
|
| 31 |
+
adminAcademyService services.AdminAcademyService
|
| 32 |
+
adminEventService services.AdminEventService
|
| 33 |
+
adminExamService services.AdminExamService
|
| 34 |
+
adminStatisticService services.AdminStatisticService
|
| 35 |
+
regionService services.RegionService
|
| 36 |
+
jWTService services.JWTService
|
| 37 |
+
academyService services.AcademyService
|
| 38 |
+
paymentService services.PaymentService
|
| 39 |
+
uploadService services.UploadService
|
| 40 |
+
problemSetService services.ProblemSetService
|
| 41 |
+
optionService services.OptionService
|
| 42 |
+
accountService services.AccountService
|
| 43 |
+
forgotPasswordService services.ForgotPasswordService
|
| 44 |
+
eventService services.EventService
|
| 45 |
+
academyExamService services.AcademyExamService
|
| 46 |
+
emailVerificationService services.EmailVerificationService
|
| 47 |
+
externalAuthService services.ExternalAuthService
|
| 48 |
eventExamService services.EventExamService
|
| 49 |
eventExamProctoringService services.EventExamProctoringService
|
| 50 |
}
|
| 51 |
+
|
| 52 |
+
func NewServicesProvider(repoProvider RepositoriesProvider, configProvider ConfigProvider) ServicesProvider {
|
| 53 |
+
regionService := services.NewRegionService(repoProvider.ProvideRegionRepository())
|
| 54 |
+
jWTService := services.NewJWTService(configProvider.ProvideJWTConfig().GetSecretKey())
|
| 55 |
+
paymentService := services.NewPaymentService(configProvider.ProvideXenditConfig().GetClient(), repoProvider.ProvideEventPaymentRepository(), repoProvider.ProvideAcademyPaymentRepository(), repoProvider.ProvideEventAssignRepository(), repoProvider.ProvideAcademyRepository())
|
| 56 |
+
academyService := services.NewAcademyService(paymentService, repoProvider.ProvideAcademyRepository())
|
| 57 |
+
storageService := services.NewSupabaseStorageService(configProvider.ProvideSupabaseConfig().GetURL(), configProvider.ProvideSupabaseConfig().GetServiceKey(), configProvider.ProvideSupabaseConfig().GetBucketName())
|
| 58 |
+
uploadService := services.NewUploadService(
|
| 59 |
+
storageService,
|
| 60 |
+
repoProvider.ProvideFileRepository(),
|
| 61 |
+
repoProvider.ProvideAccountRepository(),
|
| 62 |
+
config.NewUploadConfig(),
|
| 63 |
+
)
|
| 64 |
+
problemSetService := services.NewProblemSetService(repoProvider.ProvideProblemSetRepository(), repoProvider.ProvideQuestionsRepository(), repoProvider.ProvideProblemSetExamAssignRepository())
|
| 65 |
+
optionService := services.NewOptionService(repoProvider.ProvideOptionRepository())
|
| 66 |
+
accountService := services.NewAccountService(jWTService, repoProvider.ProvideAccountRepository(), repoProvider.ProvideAccountDetailRepository())
|
| 67 |
+
forgotPasswordService := services.NewForgotPasswordService(jWTService, repoProvider.ProvideAccountRepository(), repoProvider.ProvideForgotPasswordRepository())
|
| 68 |
+
eventService := services.NewEventService(paymentService, repoProvider.ProvideEventsRepository(), repoProvider.ProvideEventAssignRepository())
|
| 69 |
+
academyExamService := services.NewAcademyExamService(academyService, problemSetService, repoProvider.ProvideExamRepository(), repoProvider.ProvideAcademyExamAttemptRepository(), repoProvider.ProvideAcademyExamAssignRepository(), repoProvider.ProvideAcademyExamAnswerRepository(), repoProvider.ProvideAcademyResultRepository())
|
| 70 |
+
emailVerificationService := services.NewEmailVerificationService(accountService, repoProvider.ProvideEmailVerificationRepository())
|
| 71 |
+
externalAuthService := services.NewExternalAuthService(jWTService, accountService, repoProvider.ProvideExternalAuthRepository())
|
| 72 |
eventExamService := services.NewEventExamService(eventService, problemSetService, repoProvider.ProvideProblemSetExamAssignRepository(), repoProvider.ProvideExamRepository(), repoProvider.ProvideEventExamAttemptRepository(), repoProvider.ProvideEventExamAssignRepository(), repoProvider.ProvideEventExamAnswerRepository(), repoProvider.ProvideResultRepository())
|
| 73 |
eventExamProctoringService := services.NewEventExamProctoringService(eventExamService, uploadService, repoProvider.ProvideEventExamProctoringRepository())
|
| 74 |
|
| 75 |
adminEventService := services.NewAdminEventService(eventService, repoProvider.ProvideAdminEventRepository(), repoProvider.ProvideEventAssignRepository(), repoProvider.ProvideEventExamAssignRepository(), repoProvider.ProvideResultRepository())
|
| 76 |
adminExamService := services.NewAdminExamService(repoProvider.ProvideAdminExamRepository())
|
| 77 |
+
adminStatisticService := services.NewAdminStatisticService(repoProvider.ProvideAdminStatisticRepository())
|
| 78 |
+
adminAcademyService := services.NewAdminAcademyService(repoProvider.ProvideAdminAcademyRepository())
|
| 79 |
+
|
| 80 |
+
return &servicesProvider{
|
| 81 |
+
adminAcademyService: adminAcademyService,
|
| 82 |
+
adminEventService: adminEventService,
|
| 83 |
+
adminExamService: adminExamService,
|
| 84 |
+
adminStatisticService: adminStatisticService,
|
| 85 |
+
regionService: regionService,
|
| 86 |
+
jWTService: jWTService,
|
| 87 |
+
academyService: academyService,
|
| 88 |
+
paymentService: paymentService,
|
| 89 |
+
uploadService: uploadService,
|
| 90 |
+
problemSetService: problemSetService,
|
| 91 |
+
optionService: optionService,
|
| 92 |
+
accountService: accountService,
|
| 93 |
+
forgotPasswordService: forgotPasswordService,
|
| 94 |
+
eventService: eventService,
|
| 95 |
+
academyExamService: academyExamService,
|
| 96 |
+
emailVerificationService: emailVerificationService,
|
| 97 |
+
externalAuthService: externalAuthService,
|
| 98 |
eventExamService: eventExamService,
|
| 99 |
eventExamProctoringService: eventExamProctoringService,
|
| 100 |
}
|
| 101 |
}
|
| 102 |
+
|
| 103 |
+
func (s *servicesProvider) ProvideAdminAcademyService() services.AdminAcademyService {
|
| 104 |
+
return s.adminAcademyService
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
func (s *servicesProvider) ProvideAdminEventService() services.AdminEventService {
|
| 108 |
+
return s.adminEventService
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
func (s *servicesProvider) ProvideAdminExamService() services.AdminExamService {
|
| 112 |
+
return s.adminExamService
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
func (s *servicesProvider) ProvideAdminStatisticService() services.AdminStatisticService {
|
| 116 |
+
return s.adminStatisticService
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
func (s *servicesProvider) ProvideRegionService() services.RegionService {
|
| 120 |
+
return s.regionService
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
func (s *servicesProvider) ProvideJWTService() services.JWTService {
|
| 124 |
+
return s.jWTService
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
func (s *servicesProvider) ProvideAcademyService() services.AcademyService {
|
| 128 |
+
return s.academyService
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
func (s *servicesProvider) ProvidePaymentService() services.PaymentService {
|
| 132 |
+
return s.paymentService
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
func (s *servicesProvider) ProvideUploadService() services.UploadService {
|
| 136 |
+
return s.uploadService
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
func (s *servicesProvider) ProvideProblemSetService() services.ProblemSetService {
|
| 140 |
+
return s.problemSetService
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
func (s *servicesProvider) ProvideOptionService() services.OptionService {
|
| 144 |
+
return s.optionService
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
func (s *servicesProvider) ProvideAccountService() services.AccountService {
|
| 148 |
+
return s.accountService
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
func (s *servicesProvider) ProvideForgotPasswordService() services.ForgotPasswordService {
|
| 152 |
+
return s.forgotPasswordService
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
func (s *servicesProvider) ProvideEventService() services.EventService {
|
| 156 |
+
return s.eventService
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
func (s *servicesProvider) ProvideAcademyExamService() services.AcademyExamService {
|
| 160 |
+
return s.academyExamService
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
func (s *servicesProvider) ProvideEmailVerificationService() services.EmailVerificationService {
|
| 164 |
+
return s.emailVerificationService
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
func (s *servicesProvider) ProvideExternalAuthService() services.ExternalAuthService {
|
| 168 |
+
return s.externalAuthService
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
func (s *servicesProvider) ProvideEventExamService() services.EventExamService {
|
| 172 |
return s.eventExamService
|
| 173 |
}
|
| 174 |
+
|
| 175 |
+
func (s *servicesProvider) ProvideEventExamProctoringService() services.EventExamProctoringService {
|
| 176 |
+
return s.eventExamProctoringService
|
| 177 |
+
}
|
repositories/academy_repository.go
CHANGED
|
@@ -46,6 +46,7 @@ type AcademyRepository interface {
|
|
| 46 |
CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
|
| 47 |
UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
|
| 48 |
DeleteContent(ctx context.Context, id uuid.UUID) error
|
|
|
|
| 49 |
CountContentsByMaterialID(ctx context.Context, materialId uuid.UUID) (int64, error)
|
| 50 |
|
| 51 |
GetAcademyProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyProgress, error)
|
|
@@ -385,6 +386,11 @@ func (r *academyRepository) DeleteContent(ctx context.Context, id uuid.UUID) err
|
|
| 385 |
return r.db.WithContext(ctx).Delete(&entity.AcademyContent{}, "id = ?", id).Error
|
| 386 |
}
|
| 387 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
func (r *academyRepository) CountContentsByMaterialID(ctx context.Context, materialId uuid.UUID) (int64, error) {
|
| 389 |
var count int64
|
| 390 |
err := r.db.WithContext(ctx).Model(&entity.AcademyContent{}).Where("material_id = ?", materialId).Count(&count).Error
|
|
|
|
| 46 |
CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
|
| 47 |
UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
|
| 48 |
DeleteContent(ctx context.Context, id uuid.UUID) error
|
| 49 |
+
ListContents(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error)
|
| 50 |
CountContentsByMaterialID(ctx context.Context, materialId uuid.UUID) (int64, error)
|
| 51 |
|
| 52 |
GetAcademyProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyProgress, error)
|
|
|
|
| 386 |
return r.db.WithContext(ctx).Delete(&entity.AcademyContent{}, "id = ?", id).Error
|
| 387 |
}
|
| 388 |
|
| 389 |
+
func (r *academyRepository) ListContents(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error) {
|
| 390 |
+
var list []entity.AcademyContent
|
| 391 |
+
return list, r.db.WithContext(ctx).Where("material_id = ?", materialId).Order("\"order\" ASC").Find(&list).Error
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
func (r *academyRepository) CountContentsByMaterialID(ctx context.Context, materialId uuid.UUID) (int64, error) {
|
| 395 |
var count int64
|
| 396 |
err := r.db.WithContext(ctx).Model(&entity.AcademyContent{}).Where("material_id = ?", materialId).Count(&count).Error
|
repositories/admin_academy_repository.go
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package repositories
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"context"
|
| 5 |
+
|
| 6 |
+
entity "abdanhafidz.com/go-boilerplate/models/entity"
|
| 7 |
+
"github.com/google/uuid"
|
| 8 |
+
"gorm.io/gorm"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
type AdminAcademyRepository interface {
|
| 12 |
+
Atomic(ctx context.Context, fn func(r AdminAcademyRepository) error) error
|
| 13 |
+
|
| 14 |
+
GetAcademyByID(ctx context.Context, id uuid.UUID) (entity.Academy, error)
|
| 15 |
+
GetAcademyBySlug(ctx context.Context, slug string) (entity.Academy, error)
|
| 16 |
+
CreateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error)
|
| 17 |
+
UpdateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error)
|
| 18 |
+
DeleteAcademy(ctx context.Context, id uuid.UUID) error
|
| 19 |
+
CountMaterialsByAcademyID(ctx context.Context, academyId uuid.UUID) (int64, error)
|
| 20 |
+
|
| 21 |
+
GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error)
|
| 22 |
+
CreateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error)
|
| 23 |
+
UpdateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error)
|
| 24 |
+
DeleteMaterial(ctx context.Context, id uuid.UUID) error
|
| 25 |
+
ListMaterials(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error)
|
| 26 |
+
DeleteMaterialsByAcademyID(ctx context.Context, academyId uuid.UUID) error
|
| 27 |
+
DecrementMaterialOrdersGreaterThan(ctx context.Context, academyId uuid.UUID, order uint) error
|
| 28 |
+
|
| 29 |
+
GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error)
|
| 30 |
+
CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
|
| 31 |
+
UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
|
| 32 |
+
DeleteContent(ctx context.Context, id uuid.UUID) error
|
| 33 |
+
ListContents(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error)
|
| 34 |
+
CountContentsByMaterialID(ctx context.Context, materialId uuid.UUID) (int64, error)
|
| 35 |
+
DeleteContentsByMaterialID(ctx context.Context, materialId uuid.UUID) error
|
| 36 |
+
DeleteContentsByAcademyID(ctx context.Context, academyId uuid.UUID) error
|
| 37 |
+
DecrementContentOrdersGreaterThan(ctx context.Context, materialId uuid.UUID, order uint) error
|
| 38 |
+
|
| 39 |
+
DeleteContentProgressByContentID(ctx context.Context, contentId uuid.UUID) error
|
| 40 |
+
DeleteContentProgressByMaterialID(ctx context.Context, materialId uuid.UUID) error
|
| 41 |
+
DeleteMaterialProgressByMaterialID(ctx context.Context, materialId uuid.UUID) error
|
| 42 |
+
DeleteAcademyProgressByAcademyID(ctx context.Context, academyId uuid.UUID) error
|
| 43 |
+
DeleteAcademyAssignByAcademyID(ctx context.Context, academyId uuid.UUID) error
|
| 44 |
+
DeleteMaterialProgressByAcademyID(ctx context.Context, academyId uuid.UUID) error
|
| 45 |
+
DeleteContentProgressByAcademyID(ctx context.Context, academyId uuid.UUID) error
|
| 46 |
+
|
| 47 |
+
BatchRecalculateAcademyProgress(ctx context.Context, academyId uuid.UUID) error
|
| 48 |
+
BatchRecalculateMaterialProgress(ctx context.Context, materialId uuid.UUID) error
|
| 49 |
+
|
| 50 |
+
AssignAccountToAcademy(ctx context.Context, assign entity.AcademyAssign) (entity.AcademyAssign, error)
|
| 51 |
+
IsAccountAssignedToAcademy(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (bool, error)
|
| 52 |
+
ListAssignmentsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyAssign, error)
|
| 53 |
+
RemoveAssignment(ctx context.Context, id uuid.UUID) error
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
type adminAcademyRepository struct {
|
| 57 |
+
academyRepo AcademyRepository
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
func NewAdminAcademyRepository(db *gorm.DB) AdminAcademyRepository {
|
| 61 |
+
return &adminAcademyRepository{academyRepo: NewAcademyRepository(db)}
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
func (r *adminAcademyRepository) Atomic(ctx context.Context, fn func(rr AdminAcademyRepository) error) error {
|
| 65 |
+
return r.academyRepo.Atomic(ctx, func(tx AcademyRepository) error {
|
| 66 |
+
return fn(&adminAcademyRepository{academyRepo: tx})
|
| 67 |
+
})
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
func (r *adminAcademyRepository) GetAcademyByID(ctx context.Context, id uuid.UUID) (entity.Academy, error) {
|
| 71 |
+
return r.academyRepo.GetAcademyByID(ctx, id)
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
func (r *adminAcademyRepository) GetAcademyBySlug(ctx context.Context, slug string) (entity.Academy, error) {
|
| 75 |
+
return r.academyRepo.GetAcademyBySlug(ctx, slug)
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
func (r *adminAcademyRepository) CreateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
|
| 79 |
+
return r.academyRepo.CreateAcademy(ctx, a)
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
func (r *adminAcademyRepository) UpdateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
|
| 83 |
+
return r.academyRepo.UpdateAcademy(ctx, a)
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
func (r *adminAcademyRepository) DeleteAcademy(ctx context.Context, id uuid.UUID) error {
|
| 87 |
+
return r.academyRepo.DeleteAcademy(ctx, id)
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
func (r *adminAcademyRepository) CountMaterialsByAcademyID(ctx context.Context, academyId uuid.UUID) (int64, error) {
|
| 91 |
+
return r.academyRepo.CountMaterialsByAcademyID(ctx, academyId)
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
func (r *adminAcademyRepository) GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error) {
|
| 95 |
+
return r.academyRepo.GetMaterialByID(ctx, id)
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
func (r *adminAcademyRepository) CreateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error) {
|
| 99 |
+
return r.academyRepo.CreateMaterial(ctx, m)
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
func (r *adminAcademyRepository) UpdateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error) {
|
| 103 |
+
return r.academyRepo.UpdateMaterial(ctx, m)
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
func (r *adminAcademyRepository) DeleteMaterial(ctx context.Context, id uuid.UUID) error {
|
| 107 |
+
return r.academyRepo.DeleteMaterial(ctx, id)
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
func (r *adminAcademyRepository) ListMaterials(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error) {
|
| 111 |
+
return r.academyRepo.ListMaterials(ctx, academyId)
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
func (r *adminAcademyRepository) DeleteMaterialsByAcademyID(ctx context.Context, academyId uuid.UUID) error {
|
| 115 |
+
return r.academyRepo.DeleteMaterialsByAcademyID(ctx, academyId)
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
func (r *adminAcademyRepository) DecrementMaterialOrdersGreaterThan(ctx context.Context, academyId uuid.UUID, order uint) error {
|
| 119 |
+
return r.academyRepo.DecrementMaterialOrdersGreaterThan(ctx, academyId, order)
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
func (r *adminAcademyRepository) GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error) {
|
| 123 |
+
return r.academyRepo.GetContentByID(ctx, id)
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
func (r *adminAcademyRepository) CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error) {
|
| 127 |
+
return r.academyRepo.CreateContent(ctx, c)
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
func (r *adminAcademyRepository) UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error) {
|
| 131 |
+
return r.academyRepo.UpdateContent(ctx, c)
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
func (r *adminAcademyRepository) DeleteContent(ctx context.Context, id uuid.UUID) error {
|
| 135 |
+
return r.academyRepo.DeleteContent(ctx, id)
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
func (r *adminAcademyRepository) ListContents(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error) {
|
| 139 |
+
return r.academyRepo.ListContents(ctx, materialId)
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
func (r *adminAcademyRepository) CountContentsByMaterialID(ctx context.Context, materialId uuid.UUID) (int64, error) {
|
| 143 |
+
return r.academyRepo.CountContentsByMaterialID(ctx, materialId)
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
func (r *adminAcademyRepository) DeleteContentsByMaterialID(ctx context.Context, materialId uuid.UUID) error {
|
| 147 |
+
return r.academyRepo.DeleteContentsByMaterialID(ctx, materialId)
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
func (r *adminAcademyRepository) DeleteContentsByAcademyID(ctx context.Context, academyId uuid.UUID) error {
|
| 151 |
+
return r.academyRepo.DeleteContentsByAcademyID(ctx, academyId)
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
func (r *adminAcademyRepository) DecrementContentOrdersGreaterThan(ctx context.Context, materialId uuid.UUID, order uint) error {
|
| 155 |
+
return r.academyRepo.DecrementContentOrdersGreaterThan(ctx, materialId, order)
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
func (r *adminAcademyRepository) DeleteContentProgressByContentID(ctx context.Context, contentId uuid.UUID) error {
|
| 159 |
+
return r.academyRepo.DeleteContentProgressByContentID(ctx, contentId)
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
func (r *adminAcademyRepository) DeleteContentProgressByMaterialID(ctx context.Context, materialId uuid.UUID) error {
|
| 163 |
+
return r.academyRepo.DeleteContentProgressByMaterialID(ctx, materialId)
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
func (r *adminAcademyRepository) DeleteMaterialProgressByMaterialID(ctx context.Context, materialId uuid.UUID) error {
|
| 167 |
+
return r.academyRepo.DeleteMaterialProgressByMaterialID(ctx, materialId)
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
func (r *adminAcademyRepository) DeleteAcademyProgressByAcademyID(ctx context.Context, academyId uuid.UUID) error {
|
| 171 |
+
return r.academyRepo.DeleteAcademyProgressByAcademyID(ctx, academyId)
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
func (r *adminAcademyRepository) DeleteAcademyAssignByAcademyID(ctx context.Context, academyId uuid.UUID) error {
|
| 175 |
+
return r.academyRepo.DeleteAcademyAssignByAcademyID(ctx, academyId)
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
func (r *adminAcademyRepository) DeleteMaterialProgressByAcademyID(ctx context.Context, academyId uuid.UUID) error {
|
| 179 |
+
return r.academyRepo.DeleteMaterialProgressByAcademyID(ctx, academyId)
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
func (r *adminAcademyRepository) DeleteContentProgressByAcademyID(ctx context.Context, academyId uuid.UUID) error {
|
| 183 |
+
return r.academyRepo.DeleteContentProgressByAcademyID(ctx, academyId)
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
func (r *adminAcademyRepository) BatchRecalculateAcademyProgress(ctx context.Context, academyId uuid.UUID) error {
|
| 187 |
+
return r.academyRepo.BatchRecalculateAcademyProgress(ctx, academyId)
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
func (r *adminAcademyRepository) BatchRecalculateMaterialProgress(ctx context.Context, materialId uuid.UUID) error {
|
| 191 |
+
return r.academyRepo.BatchRecalculateMaterialProgress(ctx, materialId)
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
func (r *adminAcademyRepository) AssignAccountToAcademy(ctx context.Context, assign entity.AcademyAssign) (entity.AcademyAssign, error) {
|
| 195 |
+
return r.academyRepo.AssignAccountToAcademy(ctx, assign)
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
func (r *adminAcademyRepository) IsAccountAssignedToAcademy(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (bool, error) {
|
| 199 |
+
return r.academyRepo.IsAccountAssignedToAcademy(ctx, accountId, academyId)
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
func (r *adminAcademyRepository) ListAssignmentsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyAssign, error) {
|
| 203 |
+
return r.academyRepo.ListAssignmentsByAcademy(ctx, academyId)
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
func (r *adminAcademyRepository) RemoveAssignment(ctx context.Context, id uuid.UUID) error {
|
| 207 |
+
return r.academyRepo.RemoveAssignment(ctx, id)
|
| 208 |
+
}
|
repositories/admin_statistic_repository.go
ADDED
|
@@ -0,0 +1,524 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package repositories
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"context"
|
| 5 |
+
"time"
|
| 6 |
+
|
| 7 |
+
dto "abdanhafidz.com/go-boilerplate/models/dto"
|
| 8 |
+
entity "abdanhafidz.com/go-boilerplate/models/entity"
|
| 9 |
+
"github.com/google/uuid"
|
| 10 |
+
"gorm.io/gorm"
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
type AdminStatisticRepository interface {
|
| 14 |
+
GetSummary(ctx context.Context) (dto.AdminStatisticSummary, error)
|
| 15 |
+
GetMonthlyGrowth(ctx context.Context, months int) ([]dto.AdminStatisticMonthlyGrowth, error)
|
| 16 |
+
GetEventOverview(ctx context.Context) (dto.AdminEventStatisticOverview, error)
|
| 17 |
+
GetEventDetail(ctx context.Context, eventID uuid.UUID) (dto.AdminEventStatisticDetail, error)
|
| 18 |
+
GetExamOverview(ctx context.Context) (dto.AdminExamStatisticOverview, error)
|
| 19 |
+
GetExamDetail(ctx context.Context, examID uuid.UUID) (dto.AdminExamStatisticDetail, error)
|
| 20 |
+
GetAcademyOverview(ctx context.Context) (dto.AdminAcademyStatisticOverview, error)
|
| 21 |
+
GetAcademyDetail(ctx context.Context, academyID uuid.UUID) (dto.AdminAcademyStatisticDetail, error)
|
| 22 |
+
GetProblemSetOverview(ctx context.Context) (dto.AdminProblemSetStatisticOverview, error)
|
| 23 |
+
GetProblemSetDetail(ctx context.Context, problemSetID uuid.UUID) (dto.AdminProblemSetStatisticDetail, error)
|
| 24 |
+
GetQuestionOverview(ctx context.Context) (dto.AdminQuestionStatisticOverview, error)
|
| 25 |
+
GetQuestionDetail(ctx context.Context, questionID uuid.UUID) (dto.AdminQuestionStatisticDetail, error)
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
type adminStatisticRepository struct {
|
| 29 |
+
db *gorm.DB
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
func NewAdminStatisticRepository(db *gorm.DB) AdminStatisticRepository {
|
| 33 |
+
return &adminStatisticRepository{db: db}
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
func (r *adminStatisticRepository) GetSummary(ctx context.Context) (dto.AdminStatisticSummary, error) {
|
| 37 |
+
summary := dto.AdminStatisticSummary{}
|
| 38 |
+
|
| 39 |
+
if err := r.db.WithContext(ctx).Model(&entity.Account{}).Where("role = ?", "user").Count(&summary.TotalUsers).Error; err != nil {
|
| 40 |
+
return dto.AdminStatisticSummary{}, err
|
| 41 |
+
}
|
| 42 |
+
if err := r.db.WithContext(ctx).Model(&entity.Account{}).Where("role = ?", "admin").Count(&summary.TotalAdmins).Error; err != nil {
|
| 43 |
+
return dto.AdminStatisticSummary{}, err
|
| 44 |
+
}
|
| 45 |
+
if err := r.db.WithContext(ctx).Model(&entity.Account{}).Where("role = ?", "super_admin").Count(&summary.TotalSuperAdmins).Error; err != nil {
|
| 46 |
+
return dto.AdminStatisticSummary{}, err
|
| 47 |
+
}
|
| 48 |
+
if err := r.db.WithContext(ctx).Model(&entity.Academy{}).Count(&summary.TotalAcademies).Error; err != nil {
|
| 49 |
+
return dto.AdminStatisticSummary{}, err
|
| 50 |
+
}
|
| 51 |
+
if err := r.db.WithContext(ctx).Model(&entity.Events{}).Count(&summary.TotalEvents).Error; err != nil {
|
| 52 |
+
return dto.AdminStatisticSummary{}, err
|
| 53 |
+
}
|
| 54 |
+
if err := r.db.WithContext(ctx).Model(&entity.Exam{}).Count(&summary.TotalExams).Error; err != nil {
|
| 55 |
+
return dto.AdminStatisticSummary{}, err
|
| 56 |
+
}
|
| 57 |
+
if err := r.db.WithContext(ctx).Model(&entity.ProblemSet{}).Count(&summary.TotalProblemSets).Error; err != nil {
|
| 58 |
+
return dto.AdminStatisticSummary{}, err
|
| 59 |
+
}
|
| 60 |
+
if err := r.db.WithContext(ctx).Model(&entity.Questions{}).Count(&summary.TotalQuestions).Error; err != nil {
|
| 61 |
+
return dto.AdminStatisticSummary{}, err
|
| 62 |
+
}
|
| 63 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventAssign{}).Count(&summary.TotalEventParticipants).Error; err != nil {
|
| 64 |
+
return dto.AdminStatisticSummary{}, err
|
| 65 |
+
}
|
| 66 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyAssign{}).Count(&summary.TotalAcademyParticipants).Error; err != nil {
|
| 67 |
+
return dto.AdminStatisticSummary{}, err
|
| 68 |
+
}
|
| 69 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAssign{}).Count(&summary.TotalEventExamAssignments).Error; err != nil {
|
| 70 |
+
return dto.AdminStatisticSummary{}, err
|
| 71 |
+
}
|
| 72 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAssign{}).Count(&summary.TotalAcademyExamAssignments).Error; err != nil {
|
| 73 |
+
return dto.AdminStatisticSummary{}, err
|
| 74 |
+
}
|
| 75 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAttempt{}).Count(&summary.TotalEventExamAttempts).Error; err != nil {
|
| 76 |
+
return dto.AdminStatisticSummary{}, err
|
| 77 |
+
}
|
| 78 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAttempt{}).Count(&summary.TotalAcademyExamAttempts).Error; err != nil {
|
| 79 |
+
return dto.AdminStatisticSummary{}, err
|
| 80 |
+
}
|
| 81 |
+
if err := r.db.WithContext(ctx).Model(&entity.Result{}).Count(&summary.TotalEventResults).Error; err != nil {
|
| 82 |
+
return dto.AdminStatisticSummary{}, err
|
| 83 |
+
}
|
| 84 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamResult{}).Count(&summary.TotalAcademyResults).Error; err != nil {
|
| 85 |
+
return dto.AdminStatisticSummary{}, err
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
if err := r.db.WithContext(ctx).
|
| 89 |
+
Model(&entity.EventPaymentTransaction{}).
|
| 90 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 91 |
+
Count(&summary.TotalPaidEventTransactions).Error; err != nil {
|
| 92 |
+
return dto.AdminStatisticSummary{}, err
|
| 93 |
+
}
|
| 94 |
+
if err := r.db.WithContext(ctx).
|
| 95 |
+
Model(&entity.EventPaymentTransaction{}).
|
| 96 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 97 |
+
Select("COALESCE(SUM(amount), 0)").
|
| 98 |
+
Scan(&summary.PaidEventRevenue).Error; err != nil {
|
| 99 |
+
return dto.AdminStatisticSummary{}, err
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
if err := r.db.WithContext(ctx).
|
| 103 |
+
Model(&entity.AcademyPaymentTransaction{}).
|
| 104 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 105 |
+
Count(&summary.TotalPaidAcademyTransactions).Error; err != nil {
|
| 106 |
+
return dto.AdminStatisticSummary{}, err
|
| 107 |
+
}
|
| 108 |
+
if err := r.db.WithContext(ctx).
|
| 109 |
+
Model(&entity.AcademyPaymentTransaction{}).
|
| 110 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 111 |
+
Select("COALESCE(SUM(amount), 0)").
|
| 112 |
+
Scan(&summary.PaidAcademyRevenue).Error; err != nil {
|
| 113 |
+
return dto.AdminStatisticSummary{}, err
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
summary.TotalPaidRevenue = summary.PaidEventRevenue + summary.PaidAcademyRevenue
|
| 117 |
+
return summary, nil
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
func (r *adminStatisticRepository) GetMonthlyGrowth(ctx context.Context, months int) ([]dto.AdminStatisticMonthlyGrowth, error) {
|
| 121 |
+
if months < 1 {
|
| 122 |
+
months = 1
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
currentMonthStart := time.Now().UTC().Truncate(24 * time.Hour)
|
| 126 |
+
currentMonthStart = time.Date(currentMonthStart.Year(), currentMonthStart.Month(), 1, 0, 0, 0, 0, time.UTC)
|
| 127 |
+
from := currentMonthStart.AddDate(0, -(months - 1), 0)
|
| 128 |
+
|
| 129 |
+
resultMap := make(map[string]*dto.AdminStatisticMonthlyGrowth, months)
|
| 130 |
+
result := make([]dto.AdminStatisticMonthlyGrowth, 0, months)
|
| 131 |
+
|
| 132 |
+
for i := 0; i < months; i++ {
|
| 133 |
+
month := from.AddDate(0, i, 0).Format("2006-01")
|
| 134 |
+
item := dto.AdminStatisticMonthlyGrowth{Month: month}
|
| 135 |
+
result = append(result, item)
|
| 136 |
+
resultMap[month] = &result[len(result)-1]
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
type monthCountRow struct {
|
| 140 |
+
Month string `gorm:"column:month"`
|
| 141 |
+
Total int64 `gorm:"column:total"`
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
applyRows := func(rows []monthCountRow, setter func(item *dto.AdminStatisticMonthlyGrowth, value int64)) {
|
| 145 |
+
for _, row := range rows {
|
| 146 |
+
if item, ok := resultMap[row.Month]; ok {
|
| 147 |
+
setter(item, row.Total)
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
queryMonthlyCounts := func(model any, additionalWhere string, out *[]monthCountRow) error {
|
| 153 |
+
q := r.db.WithContext(ctx).
|
| 154 |
+
Model(model).
|
| 155 |
+
Select("TO_CHAR(DATE_TRUNC('month', created_at), 'YYYY-MM') AS month, COUNT(*) AS total").
|
| 156 |
+
Where("created_at >= ?", from)
|
| 157 |
+
|
| 158 |
+
if additionalWhere != "" {
|
| 159 |
+
q = q.Where(additionalWhere)
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
return q.
|
| 163 |
+
Group("DATE_TRUNC('month', created_at)").
|
| 164 |
+
Order("DATE_TRUNC('month', created_at) ASC").
|
| 165 |
+
Scan(out).Error
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
var userRows []monthCountRow
|
| 169 |
+
if err := queryMonthlyCounts(&entity.Account{}, "", &userRows); err != nil {
|
| 170 |
+
return nil, err
|
| 171 |
+
}
|
| 172 |
+
applyRows(userRows, func(item *dto.AdminStatisticMonthlyGrowth, value int64) { item.NewUsers = value })
|
| 173 |
+
|
| 174 |
+
var academyRows []monthCountRow
|
| 175 |
+
if err := queryMonthlyCounts(&entity.Academy{}, "", &academyRows); err != nil {
|
| 176 |
+
return nil, err
|
| 177 |
+
}
|
| 178 |
+
applyRows(academyRows, func(item *dto.AdminStatisticMonthlyGrowth, value int64) { item.NewAcademies = value })
|
| 179 |
+
|
| 180 |
+
var eventRows []monthCountRow
|
| 181 |
+
if err := queryMonthlyCounts(&entity.Events{}, "", &eventRows); err != nil {
|
| 182 |
+
return nil, err
|
| 183 |
+
}
|
| 184 |
+
applyRows(eventRows, func(item *dto.AdminStatisticMonthlyGrowth, value int64) { item.NewEvents = value })
|
| 185 |
+
|
| 186 |
+
var examRows []monthCountRow
|
| 187 |
+
if err := queryMonthlyCounts(&entity.Exam{}, "", &examRows); err != nil {
|
| 188 |
+
return nil, err
|
| 189 |
+
}
|
| 190 |
+
applyRows(examRows, func(item *dto.AdminStatisticMonthlyGrowth, value int64) { item.NewExams = value })
|
| 191 |
+
|
| 192 |
+
var problemSetRows []monthCountRow
|
| 193 |
+
if err := queryMonthlyCounts(&entity.ProblemSet{}, "", &problemSetRows); err != nil {
|
| 194 |
+
return nil, err
|
| 195 |
+
}
|
| 196 |
+
applyRows(problemSetRows, func(item *dto.AdminStatisticMonthlyGrowth, value int64) { item.NewProblemSets = value })
|
| 197 |
+
|
| 198 |
+
return result, nil
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
func (r *adminStatisticRepository) GetEventOverview(ctx context.Context) (dto.AdminEventStatisticOverview, error) {
|
| 202 |
+
overview := dto.AdminEventStatisticOverview{}
|
| 203 |
+
|
| 204 |
+
if err := r.db.WithContext(ctx).Model(&entity.Events{}).Count(&overview.TotalEvents).Error; err != nil {
|
| 205 |
+
return overview, err
|
| 206 |
+
}
|
| 207 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventAssign{}).Count(&overview.TotalParticipants).Error; err != nil {
|
| 208 |
+
return overview, err
|
| 209 |
+
}
|
| 210 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAssign{}).Count(&overview.TotalExamAssignments).Error; err != nil {
|
| 211 |
+
return overview, err
|
| 212 |
+
}
|
| 213 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAttempt{}).Count(&overview.TotalExamAttempts).Error; err != nil {
|
| 214 |
+
return overview, err
|
| 215 |
+
}
|
| 216 |
+
if err := r.db.WithContext(ctx).Model(&entity.Result{}).Count(&overview.TotalResults).Error; err != nil {
|
| 217 |
+
return overview, err
|
| 218 |
+
}
|
| 219 |
+
if err := r.db.WithContext(ctx).
|
| 220 |
+
Model(&entity.EventPaymentTransaction{}).
|
| 221 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 222 |
+
Count(&overview.TotalPaidTransactions).Error; err != nil {
|
| 223 |
+
return overview, err
|
| 224 |
+
}
|
| 225 |
+
if err := r.db.WithContext(ctx).
|
| 226 |
+
Model(&entity.EventPaymentTransaction{}).
|
| 227 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 228 |
+
Select("COALESCE(SUM(amount), 0)").
|
| 229 |
+
Scan(&overview.TotalPaidRevenue).Error; err != nil {
|
| 230 |
+
return overview, err
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
if overview.TotalEvents > 0 {
|
| 234 |
+
overview.AvgParticipantsPerEvent = float64(overview.TotalParticipants) / float64(overview.TotalEvents)
|
| 235 |
+
overview.AvgExamsPerEvent = float64(overview.TotalExamAssignments) / float64(overview.TotalEvents)
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
return overview, nil
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
func (r *adminStatisticRepository) GetEventDetail(ctx context.Context, eventID uuid.UUID) (dto.AdminEventStatisticDetail, error) {
|
| 242 |
+
detail := dto.AdminEventStatisticDetail{EventID: eventID.String()}
|
| 243 |
+
|
| 244 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventAssign{}).Where("event_id = ?", eventID).Count(&detail.ParticipantCount).Error; err != nil {
|
| 245 |
+
return detail, err
|
| 246 |
+
}
|
| 247 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAssign{}).Where("event_id = ?", eventID).Count(&detail.ExamAssignmentCount).Error; err != nil {
|
| 248 |
+
return detail, err
|
| 249 |
+
}
|
| 250 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAttempt{}).Where("event_id = ?", eventID).Count(&detail.ExamAttemptCount).Error; err != nil {
|
| 251 |
+
return detail, err
|
| 252 |
+
}
|
| 253 |
+
if err := r.db.WithContext(ctx).
|
| 254 |
+
Model(&entity.Result{}).
|
| 255 |
+
Joins("JOIN exam_event_attempt eea ON eea.id = result.attempt_id").
|
| 256 |
+
Where("eea.event_id = ?", eventID).
|
| 257 |
+
Count(&detail.ResultCount).Error; err != nil {
|
| 258 |
+
return detail, err
|
| 259 |
+
}
|
| 260 |
+
if err := r.db.WithContext(ctx).
|
| 261 |
+
Model(&entity.EventPaymentTransaction{}).
|
| 262 |
+
Where("event_id = ? AND status = ?", eventID, entity.PaymentStatusPaid).
|
| 263 |
+
Count(&detail.PaidTransactionCount).Error; err != nil {
|
| 264 |
+
return detail, err
|
| 265 |
+
}
|
| 266 |
+
if err := r.db.WithContext(ctx).
|
| 267 |
+
Model(&entity.EventPaymentTransaction{}).
|
| 268 |
+
Where("event_id = ? AND status = ?", eventID, entity.PaymentStatusPaid).
|
| 269 |
+
Select("COALESCE(SUM(amount), 0)").
|
| 270 |
+
Scan(&detail.PaidRevenue).Error; err != nil {
|
| 271 |
+
return detail, err
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
return detail, nil
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
func (r *adminStatisticRepository) GetExamOverview(ctx context.Context) (dto.AdminExamStatisticOverview, error) {
|
| 278 |
+
overview := dto.AdminExamStatisticOverview{}
|
| 279 |
+
|
| 280 |
+
if err := r.db.WithContext(ctx).Model(&entity.Exam{}).Count(&overview.TotalExams).Error; err != nil {
|
| 281 |
+
return overview, err
|
| 282 |
+
}
|
| 283 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAssign{}).Count(&overview.TotalEventAssignments).Error; err != nil {
|
| 284 |
+
return overview, err
|
| 285 |
+
}
|
| 286 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAssign{}).Count(&overview.TotalAcademyAssignments).Error; err != nil {
|
| 287 |
+
return overview, err
|
| 288 |
+
}
|
| 289 |
+
if err := r.db.WithContext(ctx).Model(&entity.ProblemSetExamAssign{}).Count(&overview.TotalProblemSetAssignments).Error; err != nil {
|
| 290 |
+
return overview, err
|
| 291 |
+
}
|
| 292 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAttempt{}).Count(&overview.TotalEventAttempts).Error; err != nil {
|
| 293 |
+
return overview, err
|
| 294 |
+
}
|
| 295 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAttempt{}).Count(&overview.TotalAcademyAttempts).Error; err != nil {
|
| 296 |
+
return overview, err
|
| 297 |
+
}
|
| 298 |
+
if err := r.db.WithContext(ctx).Model(&entity.Result{}).Count(&overview.TotalEventResults).Error; err != nil {
|
| 299 |
+
return overview, err
|
| 300 |
+
}
|
| 301 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamResult{}).Count(&overview.TotalAcademyResults).Error; err != nil {
|
| 302 |
+
return overview, err
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
if overview.TotalExams > 0 {
|
| 306 |
+
overview.AvgProblemSetsPerExam = float64(overview.TotalProblemSetAssignments) / float64(overview.TotalExams)
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
return overview, nil
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
func (r *adminStatisticRepository) GetExamDetail(ctx context.Context, examID uuid.UUID) (dto.AdminExamStatisticDetail, error) {
|
| 313 |
+
detail := dto.AdminExamStatisticDetail{ExamID: examID.String()}
|
| 314 |
+
|
| 315 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAssign{}).Where("exam_id = ?", examID).Count(&detail.EventAssignmentCount).Error; err != nil {
|
| 316 |
+
return detail, err
|
| 317 |
+
}
|
| 318 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAssign{}).Where("exam_id = ?", examID).Count(&detail.AcademyAssignmentCount).Error; err != nil {
|
| 319 |
+
return detail, err
|
| 320 |
+
}
|
| 321 |
+
if err := r.db.WithContext(ctx).Model(&entity.ProblemSetExamAssign{}).Where("exam_id = ?", examID).Count(&detail.ProblemSetAssignmentCount).Error; err != nil {
|
| 322 |
+
return detail, err
|
| 323 |
+
}
|
| 324 |
+
if err := r.db.WithContext(ctx).Model(&entity.EventExamAttempt{}).Where("exam_id = ?", examID).Count(&detail.EventAttemptCount).Error; err != nil {
|
| 325 |
+
return detail, err
|
| 326 |
+
}
|
| 327 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAttempt{}).Where("exam_id = ?", examID).Count(&detail.AcademyAttemptCount).Error; err != nil {
|
| 328 |
+
return detail, err
|
| 329 |
+
}
|
| 330 |
+
if err := r.db.WithContext(ctx).
|
| 331 |
+
Model(&entity.Result{}).
|
| 332 |
+
Joins("JOIN exam_event_attempt eea ON eea.id = result.attempt_id").
|
| 333 |
+
Where("eea.exam_id = ?", examID).
|
| 334 |
+
Count(&detail.EventResultCount).Error; err != nil {
|
| 335 |
+
return detail, err
|
| 336 |
+
}
|
| 337 |
+
if err := r.db.WithContext(ctx).
|
| 338 |
+
Model(&entity.AcademyExamResult{}).
|
| 339 |
+
Joins("JOIN exam_academy_attempt eaa ON eaa.id = academy_exam_result.attempt_id").
|
| 340 |
+
Where("eaa.exam_id = ?", examID).
|
| 341 |
+
Count(&detail.AcademyResultCount).Error; err != nil {
|
| 342 |
+
return detail, err
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
return detail, nil
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
func (r *adminStatisticRepository) GetAcademyOverview(ctx context.Context) (dto.AdminAcademyStatisticOverview, error) {
|
| 349 |
+
overview := dto.AdminAcademyStatisticOverview{}
|
| 350 |
+
|
| 351 |
+
if err := r.db.WithContext(ctx).Model(&entity.Academy{}).Count(&overview.TotalAcademies).Error; err != nil {
|
| 352 |
+
return overview, err
|
| 353 |
+
}
|
| 354 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyAssign{}).Count(&overview.TotalParticipants).Error; err != nil {
|
| 355 |
+
return overview, err
|
| 356 |
+
}
|
| 357 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAssign{}).Count(&overview.TotalExamAssignments).Error; err != nil {
|
| 358 |
+
return overview, err
|
| 359 |
+
}
|
| 360 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAttempt{}).Count(&overview.TotalExamAttempts).Error; err != nil {
|
| 361 |
+
return overview, err
|
| 362 |
+
}
|
| 363 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamResult{}).Count(&overview.TotalResults).Error; err != nil {
|
| 364 |
+
return overview, err
|
| 365 |
+
}
|
| 366 |
+
if err := r.db.WithContext(ctx).
|
| 367 |
+
Model(&entity.AcademyPaymentTransaction{}).
|
| 368 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 369 |
+
Count(&overview.TotalPaidTransactions).Error; err != nil {
|
| 370 |
+
return overview, err
|
| 371 |
+
}
|
| 372 |
+
if err := r.db.WithContext(ctx).
|
| 373 |
+
Model(&entity.AcademyPaymentTransaction{}).
|
| 374 |
+
Where("status = ?", entity.PaymentStatusPaid).
|
| 375 |
+
Select("COALESCE(SUM(amount), 0)").
|
| 376 |
+
Scan(&overview.TotalPaidRevenue).Error; err != nil {
|
| 377 |
+
return overview, err
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
if overview.TotalAcademies > 0 {
|
| 381 |
+
overview.AvgParticipantsPerAcademy = float64(overview.TotalParticipants) / float64(overview.TotalAcademies)
|
| 382 |
+
overview.AvgExamsPerAcademy = float64(overview.TotalExamAssignments) / float64(overview.TotalAcademies)
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
return overview, nil
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
func (r *adminStatisticRepository) GetAcademyDetail(ctx context.Context, academyID uuid.UUID) (dto.AdminAcademyStatisticDetail, error) {
|
| 389 |
+
detail := dto.AdminAcademyStatisticDetail{AcademyID: academyID.String()}
|
| 390 |
+
|
| 391 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyMaterial{}).Where("academy_id = ?", academyID).Count(&detail.MaterialCount).Error; err != nil {
|
| 392 |
+
return detail, err
|
| 393 |
+
}
|
| 394 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyAssign{}).Where("academy_id = ?", academyID).Count(&detail.ParticipantCount).Error; err != nil {
|
| 395 |
+
return detail, err
|
| 396 |
+
}
|
| 397 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAssign{}).Where("academy_id = ?", academyID).Count(&detail.ExamAssignmentCount).Error; err != nil {
|
| 398 |
+
return detail, err
|
| 399 |
+
}
|
| 400 |
+
if err := r.db.WithContext(ctx).Model(&entity.AcademyExamAttempt{}).Where("academy_id = ?", academyID).Count(&detail.ExamAttemptCount).Error; err != nil {
|
| 401 |
+
return detail, err
|
| 402 |
+
}
|
| 403 |
+
if err := r.db.WithContext(ctx).
|
| 404 |
+
Model(&entity.AcademyExamResult{}).
|
| 405 |
+
Joins("JOIN exam_academy_attempt eaa ON eaa.id = academy_exam_result.attempt_id").
|
| 406 |
+
Where("eaa.academy_id = ?", academyID).
|
| 407 |
+
Count(&detail.ResultCount).Error; err != nil {
|
| 408 |
+
return detail, err
|
| 409 |
+
}
|
| 410 |
+
if err := r.db.WithContext(ctx).
|
| 411 |
+
Model(&entity.AcademyPaymentTransaction{}).
|
| 412 |
+
Where("academy_id = ? AND status = ?", academyID, entity.PaymentStatusPaid).
|
| 413 |
+
Count(&detail.PaidTransactionCount).Error; err != nil {
|
| 414 |
+
return detail, err
|
| 415 |
+
}
|
| 416 |
+
if err := r.db.WithContext(ctx).
|
| 417 |
+
Model(&entity.AcademyPaymentTransaction{}).
|
| 418 |
+
Where("academy_id = ? AND status = ?", academyID, entity.PaymentStatusPaid).
|
| 419 |
+
Select("COALESCE(SUM(amount), 0)").
|
| 420 |
+
Scan(&detail.PaidRevenue).Error; err != nil {
|
| 421 |
+
return detail, err
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
return detail, nil
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
func (r *adminStatisticRepository) GetProblemSetOverview(ctx context.Context) (dto.AdminProblemSetStatisticOverview, error) {
|
| 428 |
+
overview := dto.AdminProblemSetStatisticOverview{}
|
| 429 |
+
|
| 430 |
+
if err := r.db.WithContext(ctx).Model(&entity.ProblemSet{}).Count(&overview.TotalProblemSets).Error; err != nil {
|
| 431 |
+
return overview, err
|
| 432 |
+
}
|
| 433 |
+
if err := r.db.WithContext(ctx).Model(&entity.Questions{}).Count(&overview.TotalQuestions).Error; err != nil {
|
| 434 |
+
return overview, err
|
| 435 |
+
}
|
| 436 |
+
if err := r.db.WithContext(ctx).Model(&entity.ProblemSetExamAssign{}).Count(&overview.TotalExamAssignments).Error; err != nil {
|
| 437 |
+
return overview, err
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
if overview.TotalProblemSets > 0 {
|
| 441 |
+
overview.AvgQuestionsPerProblemSet = float64(overview.TotalQuestions) / float64(overview.TotalProblemSets)
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
var totalExams int64
|
| 445 |
+
if err := r.db.WithContext(ctx).Model(&entity.Exam{}).Count(&totalExams).Error; err != nil {
|
| 446 |
+
return overview, err
|
| 447 |
+
}
|
| 448 |
+
if totalExams > 0 {
|
| 449 |
+
overview.AvgProblemSetsPerExam = float64(overview.TotalExamAssignments) / float64(totalExams)
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
return overview, nil
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
func (r *adminStatisticRepository) GetProblemSetDetail(ctx context.Context, problemSetID uuid.UUID) (dto.AdminProblemSetStatisticDetail, error) {
|
| 456 |
+
detail := dto.AdminProblemSetStatisticDetail{ProblemSetID: problemSetID.String()}
|
| 457 |
+
|
| 458 |
+
if err := r.db.WithContext(ctx).Model(&entity.Questions{}).Where("problem_set_id = ?", problemSetID).Count(&detail.QuestionCount).Error; err != nil {
|
| 459 |
+
return detail, err
|
| 460 |
+
}
|
| 461 |
+
if err := r.db.WithContext(ctx).Model(&entity.ProblemSetExamAssign{}).Where("problem_set_id = ?", problemSetID).Count(&detail.ExamAssignmentCount).Error; err != nil {
|
| 462 |
+
return detail, err
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
return detail, nil
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
func (r *adminStatisticRepository) GetQuestionOverview(ctx context.Context) (dto.AdminQuestionStatisticOverview, error) {
|
| 469 |
+
overview := dto.AdminQuestionStatisticOverview{}
|
| 470 |
+
|
| 471 |
+
if err := r.db.WithContext(ctx).Model(&entity.Questions{}).Count(&overview.TotalQuestions).Error; err != nil {
|
| 472 |
+
return overview, err
|
| 473 |
+
}
|
| 474 |
+
if err := r.db.WithContext(ctx).Model(&entity.Questions{}).Where("type = ?", "multiple_choice").Count(&overview.TotalMultipleChoice).Error; err != nil {
|
| 475 |
+
return overview, err
|
| 476 |
+
}
|
| 477 |
+
if err := r.db.WithContext(ctx).Model(&entity.Questions{}).Where("type = ?", "essay").Count(&overview.TotalEssay).Error; err != nil {
|
| 478 |
+
return overview, err
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
type markAgg struct {
|
| 482 |
+
AvgCorr float64 `gorm:"column:avg_corr"`
|
| 483 |
+
AvgIncorr float64 `gorm:"column:avg_incorr"`
|
| 484 |
+
AvgNull float64 `gorm:"column:avg_null"`
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
var agg markAgg
|
| 488 |
+
if err := r.db.WithContext(ctx).
|
| 489 |
+
Model(&entity.Questions{}).
|
| 490 |
+
Select("COALESCE(AVG(corr_mark), 0) AS avg_corr, COALESCE(AVG(incorr_mark), 0) AS avg_incorr, COALESCE(AVG(null_mark), 0) AS avg_null").
|
| 491 |
+
Scan(&agg).Error; err != nil {
|
| 492 |
+
return overview, err
|
| 493 |
+
}
|
| 494 |
+
overview.AvgCorrectMark = agg.AvgCorr
|
| 495 |
+
overview.AvgIncorrectMark = agg.AvgIncorr
|
| 496 |
+
overview.AvgNullMark = agg.AvgNull
|
| 497 |
+
|
| 498 |
+
return overview, nil
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
func (r *adminStatisticRepository) GetQuestionDetail(ctx context.Context, questionID uuid.UUID) (dto.AdminQuestionStatisticDetail, error) {
|
| 502 |
+
detail := dto.AdminQuestionStatisticDetail{QuestionID: questionID.String()}
|
| 503 |
+
|
| 504 |
+
var q entity.Questions
|
| 505 |
+
if err := r.db.WithContext(ctx).First(&q, "id = ?", questionID).Error; err != nil {
|
| 506 |
+
return detail, err
|
| 507 |
+
}
|
| 508 |
+
|
| 509 |
+
detail.ProblemSetID = q.ProblemSetId.String()
|
| 510 |
+
detail.QuestionType = q.Type
|
| 511 |
+
detail.CorrectMark = q.CorrMark
|
| 512 |
+
detail.IncorrectMark = q.IncorrMark
|
| 513 |
+
detail.NullMark = q.NullMark
|
| 514 |
+
|
| 515 |
+
if err := r.db.WithContext(ctx).
|
| 516 |
+
Model(&entity.ProblemSetExamAssign{}).
|
| 517 |
+
Where("problem_set_id = ?", q.ProblemSetId).
|
| 518 |
+
Distinct("exam_id").
|
| 519 |
+
Count(&detail.UsedInExamCount).Error; err != nil {
|
| 520 |
+
return detail, err
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
return detail, nil
|
| 524 |
+
}
|
router/admin_academy_router.go
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package router
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"abdanhafidz.com/go-boilerplate/provider"
|
| 5 |
+
"github.com/gin-gonic/gin"
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
func AdminAcademyRouter(router *gin.Engine, middleware provider.MiddlewareProvider, controller provider.ControllerProvider) {
|
| 9 |
+
authenticationMiddleware := middleware.ProvideAuthenticationMiddleware()
|
| 10 |
+
authorizationMiddleware := middleware.ProvideAuthorizationMiddleware()
|
| 11 |
+
adminAcademyController := controller.ProvideAdminAcademyController()
|
| 12 |
+
|
| 13 |
+
adminAcademyGroup := router.Group("/api/v1/admin_academy", authenticationMiddleware.VerifyAccount, authorizationMiddleware.VerifyAdmin)
|
| 14 |
+
{
|
| 15 |
+
adminAcademyGroup.POST("/", adminAcademyController.CreateAcademy)
|
| 16 |
+
adminAcademyGroup.GET("/id/:id/detail", adminAcademyController.GetAcademyDetail)
|
| 17 |
+
adminAcademyGroup.PUT("/id/:id", adminAcademyController.UpdateAcademy)
|
| 18 |
+
adminAcademyGroup.DELETE("/id/:id", adminAcademyController.DeleteAcademy)
|
| 19 |
+
|
| 20 |
+
adminAcademyGroup.GET("/id/:id/materials", adminAcademyController.ListMaterialsByAcademy)
|
| 21 |
+
|
| 22 |
+
adminAcademyGroup.POST("/materials", adminAcademyController.CreateMaterial)
|
| 23 |
+
adminAcademyGroup.GET("/materials/id/:id/detail", adminAcademyController.GetMaterialDetail)
|
| 24 |
+
adminAcademyGroup.PUT("/materials/id/:id", adminAcademyController.UpdateMaterial)
|
| 25 |
+
adminAcademyGroup.DELETE("/materials/id/:id", adminAcademyController.DeleteMaterial)
|
| 26 |
+
adminAcademyGroup.GET("/materials/id/:id/contents", adminAcademyController.ListContentsByMaterial)
|
| 27 |
+
|
| 28 |
+
adminAcademyGroup.POST("/contents", adminAcademyController.CreateContent)
|
| 29 |
+
adminAcademyGroup.GET("/contents/id/:id/detail", adminAcademyController.GetContentDetail)
|
| 30 |
+
adminAcademyGroup.PUT("/contents/id/:id", adminAcademyController.UpdateContent)
|
| 31 |
+
adminAcademyGroup.DELETE("/contents/id/:id", adminAcademyController.DeleteContent)
|
| 32 |
+
|
| 33 |
+
adminAcademyGroup.POST("/assign", adminAcademyController.AssignAccountToAcademy)
|
| 34 |
+
adminAcademyGroup.DELETE("/assign/:id", adminAcademyController.UnassignAccountFromAcademy)
|
| 35 |
+
adminAcademyGroup.GET("/assign/:academy_id", adminAcademyController.ListAssignmentsByAcademy)
|
| 36 |
+
}
|
| 37 |
+
}
|
router/admin_router.go
CHANGED
|
@@ -9,28 +9,8 @@ func AdminRouter(router *gin.Engine, middleware provider.MiddlewareProvider, con
|
|
| 9 |
authenticationMiddleware := middleware.ProvideAuthenticationMiddleware()
|
| 10 |
authorizationMiddleware := middleware.ProvideAuthorizationMiddleware()
|
| 11 |
|
| 12 |
-
academyController := controller.ProvideAcademyController()
|
| 13 |
authenticationController := controller.ProvideAuthenticationController()
|
| 14 |
|
| 15 |
-
// Academy Admin Routes
|
| 16 |
-
academyAdminGroup := router.Group("/api/v1/admin/academy", authenticationMiddleware.VerifyAccount, authorizationMiddleware.VerifyAdmin)
|
| 17 |
-
{
|
| 18 |
-
academyAdminGroup.POST("/", academyController.CreateAcademy)
|
| 19 |
-
academyAdminGroup.GET("/id/:id/detail", academyController.GetAcademyDetail)
|
| 20 |
-
academyAdminGroup.PUT("/id/:id", academyController.UpdateAcademy)
|
| 21 |
-
academyAdminGroup.DELETE("/id/:id", academyController.DeleteAcademy)
|
| 22 |
-
|
| 23 |
-
academyAdminGroup.POST("/materials", academyController.CreateMaterial)
|
| 24 |
-
academyAdminGroup.DELETE("/materials/:id", academyController.DeleteMaterial)
|
| 25 |
-
|
| 26 |
-
academyAdminGroup.POST("/contents", academyController.CreateContent)
|
| 27 |
-
academyAdminGroup.DELETE("/contents/:id", academyController.DeleteContent)
|
| 28 |
-
|
| 29 |
-
academyAdminGroup.POST("/assign", academyController.AssignAccountToAcademy)
|
| 30 |
-
academyAdminGroup.DELETE("/assign/:id", academyController.UnassignAccountFromAcademy)
|
| 31 |
-
academyAdminGroup.GET("/assign/:academy_id", academyController.ListAssignmentsByAcademy)
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
// Authentication Admin Routes
|
| 35 |
authAdminGroup := router.Group("/api/v1/admin/authentication", authenticationMiddleware.VerifyAccount, authorizationMiddleware.VerifySuperAdmin)
|
| 36 |
{
|
|
|
|
| 9 |
authenticationMiddleware := middleware.ProvideAuthenticationMiddleware()
|
| 10 |
authorizationMiddleware := middleware.ProvideAuthorizationMiddleware()
|
| 11 |
|
|
|
|
| 12 |
authenticationController := controller.ProvideAuthenticationController()
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
// Authentication Admin Routes
|
| 15 |
authAdminGroup := router.Group("/api/v1/admin/authentication", authenticationMiddleware.VerifyAccount, authorizationMiddleware.VerifySuperAdmin)
|
| 16 |
{
|
router/admin_statistic_router.go
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package router
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"abdanhafidz.com/go-boilerplate/provider"
|
| 5 |
+
"github.com/gin-gonic/gin"
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
func AdminStatisticRouter(router *gin.Engine, middleware provider.MiddlewareProvider, controller provider.ControllerProvider) {
|
| 9 |
+
authenticationMiddleware := middleware.ProvideAuthenticationMiddleware()
|
| 10 |
+
authorizationMiddleware := middleware.ProvideAuthorizationMiddleware()
|
| 11 |
+
|
| 12 |
+
adminStatisticController := controller.ProvideAdminStatisticController()
|
| 13 |
+
|
| 14 |
+
adminStatisticGroup := router.Group("/api/v1/admin/statistics", authenticationMiddleware.VerifyAccount, authorizationMiddleware.VerifyAdmin)
|
| 15 |
+
{
|
| 16 |
+
adminStatisticGroup.GET("/summary", adminStatisticController.GetSummary)
|
| 17 |
+
adminStatisticGroup.GET("/monthly-growth", adminStatisticController.GetMonthlyGrowth)
|
| 18 |
+
|
| 19 |
+
adminStatisticGroup.GET("/event", adminStatisticController.GetEventOverview)
|
| 20 |
+
adminStatisticGroup.GET("/event/:event_id", adminStatisticController.GetEventDetail)
|
| 21 |
+
|
| 22 |
+
adminStatisticGroup.GET("/exam", adminStatisticController.GetExamOverview)
|
| 23 |
+
adminStatisticGroup.GET("/exam/:exam_id", adminStatisticController.GetExamDetail)
|
| 24 |
+
|
| 25 |
+
adminStatisticGroup.GET("/academy", adminStatisticController.GetAcademyOverview)
|
| 26 |
+
adminStatisticGroup.GET("/academy/:academy_id", adminStatisticController.GetAcademyDetail)
|
| 27 |
+
|
| 28 |
+
adminStatisticGroup.GET("/problemset", adminStatisticController.GetProblemSetOverview)
|
| 29 |
+
adminStatisticGroup.GET("/problemset/:problemset_id", adminStatisticController.GetProblemSetDetail)
|
| 30 |
+
|
| 31 |
+
adminStatisticGroup.GET("/question", adminStatisticController.GetQuestionOverview)
|
| 32 |
+
adminStatisticGroup.GET("/question/:question_id", adminStatisticController.GetQuestionDetail)
|
| 33 |
+
}
|
| 34 |
+
}
|
router/router.go
CHANGED
|
@@ -35,9 +35,11 @@ func RunRouter(appProvider provider.AppProvider) {
|
|
| 35 |
AcademyExamRouter(router, middleware, controller)
|
| 36 |
UploadRouter(router, middleware, controller)
|
| 37 |
AdminRouter(router, middleware, controller)
|
|
|
|
| 38 |
AdminEventRouter(router, middleware, controller)
|
| 39 |
AdminExamRouter(router, middleware, controller)
|
| 40 |
AdminProblemSetRouter(router, middleware, controller)
|
|
|
|
| 41 |
SuperAdminRouter(router, middleware, controller)
|
| 42 |
PaymentCallbackRouter(router, controller)
|
| 43 |
SwaggerRouter(router)
|
|
|
|
| 35 |
AcademyExamRouter(router, middleware, controller)
|
| 36 |
UploadRouter(router, middleware, controller)
|
| 37 |
AdminRouter(router, middleware, controller)
|
| 38 |
+
AdminAcademyRouter(router, middleware, controller)
|
| 39 |
AdminEventRouter(router, middleware, controller)
|
| 40 |
AdminExamRouter(router, middleware, controller)
|
| 41 |
AdminProblemSetRouter(router, middleware, controller)
|
| 42 |
+
AdminStatisticRouter(router, middleware, controller)
|
| 43 |
SuperAdminRouter(router, middleware, controller)
|
| 44 |
PaymentCallbackRouter(router, controller)
|
| 45 |
SwaggerRouter(router)
|
services/academy_service.go
CHANGED
|
@@ -27,11 +27,17 @@ type AcademyService interface {
|
|
| 27 |
DeleteAcademy(ctx context.Context, id uuid.UUID) error
|
| 28 |
ListAcademy(ctx context.Context, accountId uuid.UUID, p entity.Pagination) ([]entity.Academy, int64, error)
|
| 29 |
|
|
|
|
|
|
|
| 30 |
CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error)
|
|
|
|
| 31 |
GetMaterial(ctx context.Context, accountId uuid.UUID, academySlug string, materialSlug string) (entity.AcademyMaterial, error)
|
| 32 |
DeleteMaterial(ctx context.Context, id uuid.UUID) error
|
| 33 |
|
|
|
|
|
|
|
| 34 |
CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error)
|
|
|
|
| 35 |
GetContent(ctx context.Context, accountId uuid.UUID, academySlug string, materialSlug string, order uint) (entity.AcademyContent, error)
|
| 36 |
DeleteContent(ctx context.Context, id uuid.UUID) error
|
| 37 |
|
|
@@ -311,6 +317,31 @@ func (s *academyService) GetMaterial(ctx context.Context, accountId uuid.UUID, a
|
|
| 311 |
return s.academyRepo.GetMaterialWithProgress(ctx, accountId, academy.Id, materialSlug)
|
| 312 |
}
|
| 313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
func (s *academyService) CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error) {
|
| 315 |
if req.AcademyId == uuid.Nil {
|
| 316 |
return entity.AcademyMaterial{}, http_error.ACADEMY_ID_REQUIRED
|
|
@@ -412,6 +443,28 @@ func (s *academyService) DeleteMaterial(ctx context.Context, id uuid.UUID) error
|
|
| 412 |
})
|
| 413 |
}
|
| 414 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
func (s *academyService) CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error) {
|
| 416 |
if req.MaterialId == uuid.Nil {
|
| 417 |
return entity.AcademyContent{}, http_error.MATERIAL_ID_REQUIRED
|
|
|
|
| 27 |
DeleteAcademy(ctx context.Context, id uuid.UUID) error
|
| 28 |
ListAcademy(ctx context.Context, accountId uuid.UUID, p entity.Pagination) ([]entity.Academy, int64, error)
|
| 29 |
|
| 30 |
+
ListMaterialsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error)
|
| 31 |
+
GetMaterialDetail(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error)
|
| 32 |
CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error)
|
| 33 |
+
UpdateMaterial(ctx context.Context, id uuid.UUID, req dto.UpdateMaterialRequest) (entity.AcademyMaterial, error)
|
| 34 |
GetMaterial(ctx context.Context, accountId uuid.UUID, academySlug string, materialSlug string) (entity.AcademyMaterial, error)
|
| 35 |
DeleteMaterial(ctx context.Context, id uuid.UUID) error
|
| 36 |
|
| 37 |
+
ListContentsByMaterial(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error)
|
| 38 |
+
GetContentDetail(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error)
|
| 39 |
CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error)
|
| 40 |
+
UpdateContent(ctx context.Context, id uuid.UUID, req dto.UpdateContentRequest) (entity.AcademyContent, error)
|
| 41 |
GetContent(ctx context.Context, accountId uuid.UUID, academySlug string, materialSlug string, order uint) (entity.AcademyContent, error)
|
| 42 |
DeleteContent(ctx context.Context, id uuid.UUID) error
|
| 43 |
|
|
|
|
| 317 |
return s.academyRepo.GetMaterialWithProgress(ctx, accountId, academy.Id, materialSlug)
|
| 318 |
}
|
| 319 |
|
| 320 |
+
func (s *academyService) ListMaterialsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error) {
|
| 321 |
+
return s.academyRepo.ListMaterials(ctx, academyId)
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
func (s *academyService) GetMaterialDetail(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error) {
|
| 325 |
+
return s.academyRepo.GetMaterialByID(ctx, id)
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
func (s *academyService) UpdateMaterial(ctx context.Context, id uuid.UUID, req dto.UpdateMaterialRequest) (entity.AcademyMaterial, error) {
|
| 329 |
+
existing, err := s.academyRepo.GetMaterialByID(ctx, id)
|
| 330 |
+
if err != nil {
|
| 331 |
+
return entity.AcademyMaterial{}, http_error.MATERIAL_NOT_FOUND
|
| 332 |
+
}
|
| 333 |
+
if req.Title != "" {
|
| 334 |
+
existing.Title = req.Title
|
| 335 |
+
}
|
| 336 |
+
if req.Description != "" {
|
| 337 |
+
existing.Description = req.Description
|
| 338 |
+
}
|
| 339 |
+
if req.Slug != "" {
|
| 340 |
+
existing.Slug = req.Slug
|
| 341 |
+
}
|
| 342 |
+
return s.academyRepo.UpdateMaterial(ctx, existing)
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
func (s *academyService) CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error) {
|
| 346 |
if req.AcademyId == uuid.Nil {
|
| 347 |
return entity.AcademyMaterial{}, http_error.ACADEMY_ID_REQUIRED
|
|
|
|
| 443 |
})
|
| 444 |
}
|
| 445 |
|
| 446 |
+
func (s *academyService) ListContentsByMaterial(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error) {
|
| 447 |
+
return s.academyRepo.ListContents(ctx, materialId)
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
func (s *academyService) GetContentDetail(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error) {
|
| 451 |
+
return s.academyRepo.GetContentByID(ctx, id)
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
func (s *academyService) UpdateContent(ctx context.Context, id uuid.UUID, req dto.UpdateContentRequest) (entity.AcademyContent, error) {
|
| 455 |
+
existing, err := s.academyRepo.GetContentByID(ctx, id)
|
| 456 |
+
if err != nil {
|
| 457 |
+
return entity.AcademyContent{}, http_error.CONTENT_NOT_FOUND
|
| 458 |
+
}
|
| 459 |
+
if req.Title != "" {
|
| 460 |
+
existing.Title = req.Title
|
| 461 |
+
}
|
| 462 |
+
if req.Contents != "" {
|
| 463 |
+
existing.Contents = req.Contents
|
| 464 |
+
}
|
| 465 |
+
return s.academyRepo.UpdateContent(ctx, existing)
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
func (s *academyService) CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error) {
|
| 469 |
if req.MaterialId == uuid.Nil {
|
| 470 |
return entity.AcademyContent{}, http_error.MATERIAL_ID_REQUIRED
|
services/admin_academy_service.go
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package services
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"context"
|
| 5 |
+
"strings"
|
| 6 |
+
"time"
|
| 7 |
+
|
| 8 |
+
"abdanhafidz.com/go-boilerplate/models/dto"
|
| 9 |
+
entity "abdanhafidz.com/go-boilerplate/models/entity"
|
| 10 |
+
http_error "abdanhafidz.com/go-boilerplate/models/error"
|
| 11 |
+
"abdanhafidz.com/go-boilerplate/repositories"
|
| 12 |
+
"abdanhafidz.com/go-boilerplate/utils"
|
| 13 |
+
"github.com/google/uuid"
|
| 14 |
+
"github.com/gosimple/slug"
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
type AdminAcademyService interface {
|
| 18 |
+
CreateAcademy(ctx context.Context, req dto.CreateAcademyRequest) (entity.Academy, error)
|
| 19 |
+
GetAcademyDetail(ctx context.Context, id uuid.UUID) (entity.Academy, error)
|
| 20 |
+
UpdateAcademy(ctx context.Context, id uuid.UUID, req dto.UpdateAcademyRequest) (entity.Academy, error)
|
| 21 |
+
DeleteAcademy(ctx context.Context, id uuid.UUID) error
|
| 22 |
+
|
| 23 |
+
ListMaterialsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error)
|
| 24 |
+
GetMaterialDetail(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error)
|
| 25 |
+
CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error)
|
| 26 |
+
UpdateMaterial(ctx context.Context, id uuid.UUID, req dto.UpdateMaterialRequest) (entity.AcademyMaterial, error)
|
| 27 |
+
DeleteMaterial(ctx context.Context, id uuid.UUID) error
|
| 28 |
+
|
| 29 |
+
ListContentsByMaterial(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error)
|
| 30 |
+
GetContentDetail(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error)
|
| 31 |
+
CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error)
|
| 32 |
+
UpdateContent(ctx context.Context, id uuid.UUID, req dto.UpdateContentRequest) (entity.AcademyContent, error)
|
| 33 |
+
DeleteContent(ctx context.Context, id uuid.UUID) error
|
| 34 |
+
|
| 35 |
+
AssignAccountToAcademy(ctx context.Context, academyId uuid.UUID, accountId uuid.UUID) (entity.AcademyAssign, error)
|
| 36 |
+
UnassignAccountFromAcademy(ctx context.Context, id uuid.UUID) error
|
| 37 |
+
ListAssignmentsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyAssign, error)
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
type adminAcademyService struct {
|
| 41 |
+
repo repositories.AdminAcademyRepository
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
func NewAdminAcademyService(repo repositories.AdminAcademyRepository) AdminAcademyService {
|
| 45 |
+
return &adminAcademyService{repo: repo}
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
func (s *adminAcademyService) CreateAcademy(ctx context.Context, req dto.CreateAcademyRequest) (entity.Academy, error) {
|
| 49 |
+
if strings.TrimSpace(req.Title) == "" {
|
| 50 |
+
return entity.Academy{}, http_error.TITLE_REQUIRED
|
| 51 |
+
}
|
| 52 |
+
if strings.TrimSpace(req.Code) == "" {
|
| 53 |
+
return entity.Academy{}, http_error.CODE_REQUIRED
|
| 54 |
+
}
|
| 55 |
+
if strings.TrimSpace(req.Description) == "" {
|
| 56 |
+
return entity.Academy{}, http_error.DESCRIPTION_REQUIRED
|
| 57 |
+
}
|
| 58 |
+
if strings.TrimSpace(req.ImageUrl) == "" {
|
| 59 |
+
return entity.Academy{}, http_error.IMAGE_REQUIRED
|
| 60 |
+
}
|
| 61 |
+
if err := utils.ValidateCode(req.Code); err != nil {
|
| 62 |
+
return entity.Academy{}, err
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
slugVal := req.Slug
|
| 66 |
+
if slugVal == "" {
|
| 67 |
+
slugVal = slug.Make(req.Title)
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
if _, err := s.repo.GetAcademyBySlug(ctx, slugVal); err == nil {
|
| 71 |
+
return entity.Academy{}, http_error.DUPLICATE_DATA
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
a := entity.Academy{
|
| 75 |
+
Id: uuid.New(),
|
| 76 |
+
Title: req.Title,
|
| 77 |
+
Slug: slugVal,
|
| 78 |
+
Code: req.Code,
|
| 79 |
+
IsPublic: req.IsPublic,
|
| 80 |
+
Description: req.Description,
|
| 81 |
+
ImageUrl: req.ImageUrl,
|
| 82 |
+
MaterialsCount: 0,
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
return s.repo.CreateAcademy(ctx, a)
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
func (s *adminAcademyService) GetAcademyDetail(ctx context.Context, id uuid.UUID) (entity.Academy, error) {
|
| 89 |
+
return s.repo.GetAcademyByID(ctx, id)
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
func (s *adminAcademyService) UpdateAcademy(ctx context.Context, id uuid.UUID, req dto.UpdateAcademyRequest) (entity.Academy, error) {
|
| 93 |
+
existing, err := s.repo.GetAcademyByID(ctx, id)
|
| 94 |
+
if err != nil {
|
| 95 |
+
return entity.Academy{}, http_error.ACADEMY_NOT_FOUND
|
| 96 |
+
}
|
| 97 |
+
if req.Title != "" {
|
| 98 |
+
existing.Title = req.Title
|
| 99 |
+
}
|
| 100 |
+
if req.Description != "" {
|
| 101 |
+
existing.Description = req.Description
|
| 102 |
+
}
|
| 103 |
+
if req.Slug != "" {
|
| 104 |
+
existing.Slug = req.Slug
|
| 105 |
+
}
|
| 106 |
+
if req.ImageUrl != "" {
|
| 107 |
+
existing.ImageUrl = req.ImageUrl
|
| 108 |
+
}
|
| 109 |
+
if req.IsPublic != nil {
|
| 110 |
+
existing.IsPublic = *req.IsPublic
|
| 111 |
+
}
|
| 112 |
+
return s.repo.UpdateAcademy(ctx, existing)
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
func (s *adminAcademyService) DeleteAcademy(ctx context.Context, id uuid.UUID) error {
|
| 116 |
+
if _, err := s.repo.GetAcademyByID(ctx, id); err != nil {
|
| 117 |
+
return http_error.ACADEMY_NOT_FOUND
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
return s.repo.Atomic(ctx, func(txRepo repositories.AdminAcademyRepository) error {
|
| 121 |
+
if err := txRepo.DeleteAcademyAssignByAcademyID(ctx, id); err != nil {
|
| 122 |
+
return err
|
| 123 |
+
}
|
| 124 |
+
if err := txRepo.DeleteAcademyProgressByAcademyID(ctx, id); err != nil {
|
| 125 |
+
return err
|
| 126 |
+
}
|
| 127 |
+
if err := txRepo.DeleteMaterialProgressByAcademyID(ctx, id); err != nil {
|
| 128 |
+
return err
|
| 129 |
+
}
|
| 130 |
+
if err := txRepo.DeleteContentProgressByAcademyID(ctx, id); err != nil {
|
| 131 |
+
return err
|
| 132 |
+
}
|
| 133 |
+
if err := txRepo.DeleteContentsByAcademyID(ctx, id); err != nil {
|
| 134 |
+
return err
|
| 135 |
+
}
|
| 136 |
+
if err := txRepo.DeleteMaterialsByAcademyID(ctx, id); err != nil {
|
| 137 |
+
return err
|
| 138 |
+
}
|
| 139 |
+
return txRepo.DeleteAcademy(ctx, id)
|
| 140 |
+
})
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
func (s *adminAcademyService) ListMaterialsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error) {
|
| 144 |
+
return s.repo.ListMaterials(ctx, academyId)
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
func (s *adminAcademyService) GetMaterialDetail(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error) {
|
| 148 |
+
return s.repo.GetMaterialByID(ctx, id)
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
func (s *adminAcademyService) CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error) {
|
| 152 |
+
if req.AcademyId == uuid.Nil {
|
| 153 |
+
return entity.AcademyMaterial{}, http_error.ACADEMY_ID_REQUIRED
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
slugVal := req.Slug
|
| 157 |
+
if slugVal == "" {
|
| 158 |
+
slugVal = slug.Make(req.Title)
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
var createdMaterial entity.AcademyMaterial
|
| 162 |
+
err := s.repo.Atomic(ctx, func(txRepo repositories.AdminAcademyRepository) error {
|
| 163 |
+
orderCount, _ := txRepo.CountMaterialsByAcademyID(ctx, req.AcademyId)
|
| 164 |
+
|
| 165 |
+
m := entity.AcademyMaterial{
|
| 166 |
+
Id: uuid.New(),
|
| 167 |
+
AcademyId: req.AcademyId,
|
| 168 |
+
Title: req.Title,
|
| 169 |
+
Slug: slugVal,
|
| 170 |
+
Description: req.Description,
|
| 171 |
+
Order: uint(orderCount + 1),
|
| 172 |
+
ContentsCount: 0,
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
res, err := txRepo.CreateMaterial(ctx, m)
|
| 176 |
+
if err != nil {
|
| 177 |
+
return err
|
| 178 |
+
}
|
| 179 |
+
createdMaterial = res
|
| 180 |
+
|
| 181 |
+
realCount, err := txRepo.CountMaterialsByAcademyID(ctx, req.AcademyId)
|
| 182 |
+
if err != nil {
|
| 183 |
+
return err
|
| 184 |
+
}
|
| 185 |
+
academy, _ := txRepo.GetAcademyByID(ctx, req.AcademyId)
|
| 186 |
+
academy.MaterialsCount = int64(realCount)
|
| 187 |
+
if _, err := txRepo.UpdateAcademy(ctx, academy); err != nil {
|
| 188 |
+
return err
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
if err := txRepo.BatchRecalculateAcademyProgress(ctx, req.AcademyId); err != nil {
|
| 192 |
+
return err
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
return nil
|
| 196 |
+
})
|
| 197 |
+
if err != nil {
|
| 198 |
+
return entity.AcademyMaterial{}, err
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
return createdMaterial, nil
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
func (s *adminAcademyService) UpdateMaterial(ctx context.Context, id uuid.UUID, req dto.UpdateMaterialRequest) (entity.AcademyMaterial, error) {
|
| 205 |
+
existing, err := s.repo.GetMaterialByID(ctx, id)
|
| 206 |
+
if err != nil {
|
| 207 |
+
return entity.AcademyMaterial{}, http_error.MATERIAL_NOT_FOUND
|
| 208 |
+
}
|
| 209 |
+
if req.Title != "" {
|
| 210 |
+
existing.Title = req.Title
|
| 211 |
+
}
|
| 212 |
+
if req.Description != "" {
|
| 213 |
+
existing.Description = req.Description
|
| 214 |
+
}
|
| 215 |
+
if req.Slug != "" {
|
| 216 |
+
existing.Slug = req.Slug
|
| 217 |
+
}
|
| 218 |
+
return s.repo.UpdateMaterial(ctx, existing)
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
func (s *adminAcademyService) DeleteMaterial(ctx context.Context, id uuid.UUID) error {
|
| 222 |
+
m, err := s.repo.GetMaterialByID(ctx, id)
|
| 223 |
+
if err != nil {
|
| 224 |
+
return http_error.MATERIAL_NOT_FOUND
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
return s.repo.Atomic(ctx, func(txRepo repositories.AdminAcademyRepository) error {
|
| 228 |
+
if err := txRepo.DeleteContentProgressByMaterialID(ctx, id); err != nil {
|
| 229 |
+
return err
|
| 230 |
+
}
|
| 231 |
+
if err := txRepo.DeleteMaterialProgressByMaterialID(ctx, id); err != nil {
|
| 232 |
+
return err
|
| 233 |
+
}
|
| 234 |
+
if err := txRepo.DeleteContentsByMaterialID(ctx, id); err != nil {
|
| 235 |
+
return err
|
| 236 |
+
}
|
| 237 |
+
if err := txRepo.DeleteMaterial(ctx, id); err != nil {
|
| 238 |
+
return err
|
| 239 |
+
}
|
| 240 |
+
if err := txRepo.DecrementMaterialOrdersGreaterThan(ctx, m.AcademyId, m.Order); err != nil {
|
| 241 |
+
return err
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
realCount, err := txRepo.CountMaterialsByAcademyID(ctx, m.AcademyId)
|
| 245 |
+
if err != nil {
|
| 246 |
+
return err
|
| 247 |
+
}
|
| 248 |
+
academy, _ := txRepo.GetAcademyByID(ctx, m.AcademyId)
|
| 249 |
+
academy.MaterialsCount = int64(realCount)
|
| 250 |
+
if _, err := txRepo.UpdateAcademy(ctx, academy); err != nil {
|
| 251 |
+
return err
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
if err := txRepo.BatchRecalculateAcademyProgress(ctx, m.AcademyId); err != nil {
|
| 255 |
+
return err
|
| 256 |
+
}
|
| 257 |
+
return nil
|
| 258 |
+
})
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
func (s *adminAcademyService) ListContentsByMaterial(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error) {
|
| 262 |
+
return s.repo.ListContents(ctx, materialId)
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
func (s *adminAcademyService) GetContentDetail(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error) {
|
| 266 |
+
return s.repo.GetContentByID(ctx, id)
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
func (s *adminAcademyService) CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error) {
|
| 270 |
+
if req.MaterialId == uuid.Nil {
|
| 271 |
+
return entity.AcademyContent{}, http_error.MATERIAL_ID_REQUIRED
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
var createdContent entity.AcademyContent
|
| 275 |
+
err := s.repo.Atomic(ctx, func(txRepo repositories.AdminAcademyRepository) error {
|
| 276 |
+
m, err := txRepo.GetMaterialByID(ctx, req.MaterialId)
|
| 277 |
+
if err != nil {
|
| 278 |
+
return http_error.MATERIAL_NOT_FOUND
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
count, _ := txRepo.CountContentsByMaterialID(ctx, req.MaterialId)
|
| 282 |
+
c := entity.AcademyContent{
|
| 283 |
+
Id: uuid.New(),
|
| 284 |
+
MaterialId: req.MaterialId,
|
| 285 |
+
Title: req.Title,
|
| 286 |
+
Contents: req.Contents,
|
| 287 |
+
Order: uint(count + 1),
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
res, err := txRepo.CreateContent(ctx, c)
|
| 291 |
+
if err != nil {
|
| 292 |
+
return err
|
| 293 |
+
}
|
| 294 |
+
createdContent = res
|
| 295 |
+
|
| 296 |
+
realCount, err := txRepo.CountContentsByMaterialID(ctx, req.MaterialId)
|
| 297 |
+
if err != nil {
|
| 298 |
+
return err
|
| 299 |
+
}
|
| 300 |
+
m.ContentsCount = realCount
|
| 301 |
+
if _, err := txRepo.UpdateMaterial(ctx, m); err != nil {
|
| 302 |
+
return err
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
if err := txRepo.BatchRecalculateMaterialProgress(ctx, req.MaterialId); err != nil {
|
| 306 |
+
return err
|
| 307 |
+
}
|
| 308 |
+
if err := txRepo.BatchRecalculateAcademyProgress(ctx, m.AcademyId); err != nil {
|
| 309 |
+
return err
|
| 310 |
+
}
|
| 311 |
+
return nil
|
| 312 |
+
})
|
| 313 |
+
|
| 314 |
+
return createdContent, err
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
func (s *adminAcademyService) UpdateContent(ctx context.Context, id uuid.UUID, req dto.UpdateContentRequest) (entity.AcademyContent, error) {
|
| 318 |
+
existing, err := s.repo.GetContentByID(ctx, id)
|
| 319 |
+
if err != nil {
|
| 320 |
+
return entity.AcademyContent{}, http_error.CONTENT_NOT_FOUND
|
| 321 |
+
}
|
| 322 |
+
if req.Title != "" {
|
| 323 |
+
existing.Title = req.Title
|
| 324 |
+
}
|
| 325 |
+
if req.Contents != "" {
|
| 326 |
+
existing.Contents = req.Contents
|
| 327 |
+
}
|
| 328 |
+
return s.repo.UpdateContent(ctx, existing)
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
func (s *adminAcademyService) DeleteContent(ctx context.Context, id uuid.UUID) error {
|
| 332 |
+
c, err := s.repo.GetContentByID(ctx, id)
|
| 333 |
+
if err != nil {
|
| 334 |
+
return http_error.CONTENT_NOT_FOUND
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
return s.repo.Atomic(ctx, func(txRepo repositories.AdminAcademyRepository) error {
|
| 338 |
+
if err := txRepo.DeleteContentProgressByContentID(ctx, id); err != nil {
|
| 339 |
+
return err
|
| 340 |
+
}
|
| 341 |
+
if err := txRepo.DeleteContent(ctx, id); err != nil {
|
| 342 |
+
return err
|
| 343 |
+
}
|
| 344 |
+
if err := txRepo.DecrementContentOrdersGreaterThan(ctx, c.MaterialId, c.Order); err != nil {
|
| 345 |
+
return err
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
realCount, err := txRepo.CountContentsByMaterialID(ctx, c.MaterialId)
|
| 349 |
+
if err != nil {
|
| 350 |
+
return err
|
| 351 |
+
}
|
| 352 |
+
material, _ := txRepo.GetMaterialByID(ctx, c.MaterialId)
|
| 353 |
+
material.ContentsCount = realCount
|
| 354 |
+
if _, err := txRepo.UpdateMaterial(ctx, material); err != nil {
|
| 355 |
+
return err
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
if err := txRepo.BatchRecalculateMaterialProgress(ctx, c.MaterialId); err != nil {
|
| 359 |
+
return err
|
| 360 |
+
}
|
| 361 |
+
if err := txRepo.BatchRecalculateAcademyProgress(ctx, material.AcademyId); err != nil {
|
| 362 |
+
return err
|
| 363 |
+
}
|
| 364 |
+
return nil
|
| 365 |
+
})
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
func (s *adminAcademyService) AssignAccountToAcademy(ctx context.Context, academyId uuid.UUID, accountId uuid.UUID) (entity.AcademyAssign, error) {
|
| 369 |
+
if academyId == uuid.Nil || accountId == uuid.Nil {
|
| 370 |
+
return entity.AcademyAssign{}, http_error.BAD_REQUEST_ERROR
|
| 371 |
+
}
|
| 372 |
+
if _, err := s.repo.GetAcademyByID(ctx, academyId); err != nil {
|
| 373 |
+
return entity.AcademyAssign{}, http_error.ACADEMY_NOT_FOUND
|
| 374 |
+
}
|
| 375 |
+
assigned, err := s.repo.IsAccountAssignedToAcademy(ctx, accountId, academyId)
|
| 376 |
+
if err != nil {
|
| 377 |
+
return entity.AcademyAssign{}, err
|
| 378 |
+
}
|
| 379 |
+
if assigned {
|
| 380 |
+
return entity.AcademyAssign{}, http_error.DUPLICATE_DATA
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
assign := entity.AcademyAssign{
|
| 384 |
+
Id: uuid.New(),
|
| 385 |
+
AccountId: accountId,
|
| 386 |
+
AcademyId: academyId,
|
| 387 |
+
CreatedAt: time.Now(),
|
| 388 |
+
}
|
| 389 |
+
return s.repo.AssignAccountToAcademy(ctx, assign)
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
func (s *adminAcademyService) UnassignAccountFromAcademy(ctx context.Context, id uuid.UUID) error {
|
| 393 |
+
if id == uuid.Nil {
|
| 394 |
+
return http_error.BAD_REQUEST_ERROR
|
| 395 |
+
}
|
| 396 |
+
return s.repo.RemoveAssignment(ctx, id)
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
func (s *adminAcademyService) ListAssignmentsByAcademy(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyAssign, error) {
|
| 400 |
+
if academyId == uuid.Nil {
|
| 401 |
+
return nil, http_error.BAD_REQUEST_ERROR
|
| 402 |
+
}
|
| 403 |
+
return s.repo.ListAssignmentsByAcademy(ctx, academyId)
|
| 404 |
+
}
|
services/admin_statistic_service.go
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package services
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"context"
|
| 5 |
+
|
| 6 |
+
dto "abdanhafidz.com/go-boilerplate/models/dto"
|
| 7 |
+
"abdanhafidz.com/go-boilerplate/repositories"
|
| 8 |
+
"github.com/google/uuid"
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
type AdminStatisticService interface {
|
| 12 |
+
GetSummary(ctx context.Context) (dto.AdminStatisticSummary, error)
|
| 13 |
+
GetMonthlyGrowth(ctx context.Context, months int) ([]dto.AdminStatisticMonthlyGrowth, error)
|
| 14 |
+
GetEventOverview(ctx context.Context) (dto.AdminEventStatisticOverview, error)
|
| 15 |
+
GetEventDetail(ctx context.Context, eventID uuid.UUID) (dto.AdminEventStatisticDetail, error)
|
| 16 |
+
GetExamOverview(ctx context.Context) (dto.AdminExamStatisticOverview, error)
|
| 17 |
+
GetExamDetail(ctx context.Context, examID uuid.UUID) (dto.AdminExamStatisticDetail, error)
|
| 18 |
+
GetAcademyOverview(ctx context.Context) (dto.AdminAcademyStatisticOverview, error)
|
| 19 |
+
GetAcademyDetail(ctx context.Context, academyID uuid.UUID) (dto.AdminAcademyStatisticDetail, error)
|
| 20 |
+
GetProblemSetOverview(ctx context.Context) (dto.AdminProblemSetStatisticOverview, error)
|
| 21 |
+
GetProblemSetDetail(ctx context.Context, problemSetID uuid.UUID) (dto.AdminProblemSetStatisticDetail, error)
|
| 22 |
+
GetQuestionOverview(ctx context.Context) (dto.AdminQuestionStatisticOverview, error)
|
| 23 |
+
GetQuestionDetail(ctx context.Context, questionID uuid.UUID) (dto.AdminQuestionStatisticDetail, error)
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
type adminStatisticService struct {
|
| 27 |
+
adminStatisticRepo repositories.AdminStatisticRepository
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
func NewAdminStatisticService(adminStatisticRepo repositories.AdminStatisticRepository) AdminStatisticService {
|
| 31 |
+
return &adminStatisticService{adminStatisticRepo: adminStatisticRepo}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
func (s *adminStatisticService) GetSummary(ctx context.Context) (dto.AdminStatisticSummary, error) {
|
| 35 |
+
summary, err := s.adminStatisticRepo.GetSummary(ctx)
|
| 36 |
+
if err != nil {
|
| 37 |
+
return dto.AdminStatisticSummary{}, err
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
if summary.TotalEvents > 0 {
|
| 41 |
+
summary.AverageParticipantsPerEvent = float64(summary.TotalEventParticipants) / float64(summary.TotalEvents)
|
| 42 |
+
summary.AverageExamsPerEvent = float64(summary.TotalEventExamAssignments) / float64(summary.TotalEvents)
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
return summary, nil
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
func (s *adminStatisticService) GetMonthlyGrowth(ctx context.Context, months int) ([]dto.AdminStatisticMonthlyGrowth, error) {
|
| 49 |
+
if months < 1 {
|
| 50 |
+
months = 6
|
| 51 |
+
}
|
| 52 |
+
if months > 24 {
|
| 53 |
+
months = 24
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
return s.adminStatisticRepo.GetMonthlyGrowth(ctx, months)
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
func (s *adminStatisticService) GetEventOverview(ctx context.Context) (dto.AdminEventStatisticOverview, error) {
|
| 60 |
+
return s.adminStatisticRepo.GetEventOverview(ctx)
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
func (s *adminStatisticService) GetEventDetail(ctx context.Context, eventID uuid.UUID) (dto.AdminEventStatisticDetail, error) {
|
| 64 |
+
return s.adminStatisticRepo.GetEventDetail(ctx, eventID)
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
func (s *adminStatisticService) GetExamOverview(ctx context.Context) (dto.AdminExamStatisticOverview, error) {
|
| 68 |
+
return s.adminStatisticRepo.GetExamOverview(ctx)
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
func (s *adminStatisticService) GetExamDetail(ctx context.Context, examID uuid.UUID) (dto.AdminExamStatisticDetail, error) {
|
| 72 |
+
return s.adminStatisticRepo.GetExamDetail(ctx, examID)
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
func (s *adminStatisticService) GetAcademyOverview(ctx context.Context) (dto.AdminAcademyStatisticOverview, error) {
|
| 76 |
+
return s.adminStatisticRepo.GetAcademyOverview(ctx)
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
func (s *adminStatisticService) GetAcademyDetail(ctx context.Context, academyID uuid.UUID) (dto.AdminAcademyStatisticDetail, error) {
|
| 80 |
+
return s.adminStatisticRepo.GetAcademyDetail(ctx, academyID)
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
func (s *adminStatisticService) GetProblemSetOverview(ctx context.Context) (dto.AdminProblemSetStatisticOverview, error) {
|
| 84 |
+
return s.adminStatisticRepo.GetProblemSetOverview(ctx)
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
func (s *adminStatisticService) GetProblemSetDetail(ctx context.Context, problemSetID uuid.UUID) (dto.AdminProblemSetStatisticDetail, error) {
|
| 88 |
+
return s.adminStatisticRepo.GetProblemSetDetail(ctx, problemSetID)
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
func (s *adminStatisticService) GetQuestionOverview(ctx context.Context) (dto.AdminQuestionStatisticOverview, error) {
|
| 92 |
+
return s.adminStatisticRepo.GetQuestionOverview(ctx)
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
func (s *adminStatisticService) GetQuestionDetail(ctx context.Context, questionID uuid.UUID) (dto.AdminQuestionStatisticDetail, error) {
|
| 96 |
+
return s.adminStatisticRepo.GetQuestionDetail(ctx, questionID)
|
| 97 |
+
}
|