lifedebugger commited on
Commit
f18c71f
·
1 Parent(s): 92a54e4

Deploy files from GitHub repository

Browse files
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 Event Management",
1418
  "item": [
1419
  {
1420
- "name": "List Events (Admin View)",
1421
  "request": {
1422
  "method": "GET",
1423
  "header": [
@@ -1428,7 +2056,7 @@
1428
  }
1429
  ],
1430
  "url": {
1431
- "raw": "{{base_url}}/api/v1/admin/events/?page=1&limit=10&search=&sortBy=created_at&order=desc",
1432
  "host": [
1433
  "{{base_url}}"
1434
  ],
@@ -1436,63 +2064,26 @@
1436
  "api",
1437
  "v1",
1438
  "admin",
1439
- "events",
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": "Create Event",
1476
  "request": {
1477
- "method": "POST",
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/events/",
1496
  "host": [
1497
  "{{base_url}}"
1498
  ],
@@ -1500,36 +2091,32 @@
1500
  "api",
1501
  "v1",
1502
  "admin",
1503
- "events",
1504
- ""
 
 
 
 
 
 
1505
  ]
1506
- },
1507
- "description": "Create a new event."
1508
  },
1509
  "response": []
1510
  },
1511
  {
1512
- "name": "Update Event",
1513
  "request": {
1514
- "method": "PUT",
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/events/:event_id",
1533
  "host": [
1534
  "{{base_url}}"
1535
  ],
@@ -1537,24 +2124,17 @@
1537
  "api",
1538
  "v1",
1539
  "admin",
1540
- "events",
1541
- ":event_id"
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": "Delete Event",
1556
  "request": {
1557
- "method": "DELETE",
1558
  "header": [
1559
  {
1560
  "key": "Authorization",
@@ -1563,7 +2143,7 @@
1563
  }
1564
  ],
1565
  "url": {
1566
- "raw": "{{base_url}}/api/v1/admin/events/:event_id",
1567
  "host": [
1568
  "{{base_url}}"
1569
  ],
@@ -1571,7 +2151,8 @@
1571
  "api",
1572
  "v1",
1573
  "admin",
1574
- "events",
 
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": "Participants - List",
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/events/:event_id/participants?page=1&limit=10&search=&sortBy=assigned_at&order=desc",
1601
- "host": [
1602
- "{{base_url}}"
1603
- ],
1604
- "path": [
1605
- "api",
1606
- "v1",
1607
- "admin",
1608
- "events",
1609
- ":event_id",
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": "Candidates - List",
1652
  "request": {
1653
  "method": "GET",
1654
  "header": [
@@ -1659,7 +2204,7 @@
1659
  }
1660
  ],
1661
  "url": {
1662
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/candidate?page=1&limit=10&search=&sortBy=created_at&orderBy=desc",
1663
  "host": [
1664
  "{{base_url}}"
1665
  ],
@@ -1667,70 +2212,60 @@
1667
  "api",
1668
  "v1",
1669
  "admin",
1670
- "events",
1671
- ":event_id",
1672
- "candidate"
1673
  ],
1674
  "variable": [
1675
  {
1676
- "key": "event_id",
1677
- "value": "{{event_id}}"
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": "Participants - Add (Manual Assign)",
1714
  "request": {
1715
- "method": "POST",
1716
  "header": [
1717
  {
1718
- "key": "Content-Type",
1719
- "value": "application/json",
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/events/:event_id/participants",
1734
  "host": [
1735
  "{{base_url}}"
1736
  ],
@@ -1738,25 +2273,24 @@
1738
  "api",
1739
  "v1",
1740
  "admin",
1741
- "events",
1742
- ":event_id",
1743
- "participants"
1744
  ],
1745
  "variable": [
1746
  {
1747
- "key": "event_id",
1748
- "value": "{{event_id}}"
1749
  }
1750
  ]
1751
- },
1752
- "description": "Manually assign a user to an event. Bypasses payment."
1753
  },
1754
  "response": []
1755
  },
1756
  {
1757
- "name": "Participants - Remove",
1758
  "request": {
1759
- "method": "DELETE",
1760
  "header": [
1761
  {
1762
  "key": "Authorization",
@@ -1765,7 +2299,7 @@
1765
  }
1766
  ],
1767
  "url": {
1768
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/participants/:user_id",
1769
  "host": [
1770
  "{{base_url}}"
1771
  ],
@@ -1773,28 +2307,15 @@
1773
  "api",
1774
  "v1",
1775
  "admin",
1776
- "events",
1777
- ":event_id",
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": "Exams - List Event Exams",
1798
  "request": {
1799
  "method": "GET",
1800
  "header": [
@@ -1805,7 +2326,7 @@
1805
  }
1806
  ],
1807
  "url": {
1808
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/exams?page=1&limit=10&search=&sortBy=created_at&order=desc",
1809
  "host": [
1810
  "{{base_url}}"
1811
  ],
@@ -1813,50 +2334,22 @@
1813
  "api",
1814
  "v1",
1815
  "admin",
1816
- "events",
1817
- ":event_id",
1818
- "exams"
1819
  ],
1820
  "variable": [
1821
  {
1822
- "key": "event_id",
1823
- "value": "{{event_id}}"
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": "Exams - List Exam Candidates",
1860
  "request": {
1861
  "method": "GET",
1862
  "header": [
@@ -1867,7 +2360,7 @@
1867
  }
1868
  ],
1869
  "url": {
1870
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/candidate?page=1&limit=10&search=&sortBy=created_at&orderBy=desc",
1871
  "host": [
1872
  "{{base_url}}"
1873
  ],
@@ -1875,53 +2368,17 @@
1875
  "api",
1876
  "v1",
1877
  "admin",
1878
- "events",
1879
- ":event_id",
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": "Exams - Remove Exam from Event",
1923
  "request": {
1924
- "method": "DELETE",
1925
  "header": [
1926
  {
1927
  "key": "Authorization",
@@ -1930,7 +2387,7 @@
1930
  }
1931
  ],
1932
  "url": {
1933
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id",
1934
  "host": [
1935
  "{{base_url}}"
1936
  ],
@@ -1938,28 +2395,27 @@
1938
  "api",
1939
  "v1",
1940
  "admin",
1941
- "events",
1942
- ":event_id",
1943
- "exams",
1944
- ":exam_id"
1945
  ],
1946
  "variable": [
1947
  {
1948
- "key": "event_id",
1949
- "value": "{{event_id}}"
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": "Results - List Exam Results",
1963
  "request": {
1964
  "method": "GET",
1965
  "header": [
@@ -1970,7 +2426,7 @@
1970
  }
1971
  ],
1972
  "url": {
1973
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id/results?page=1&limit=10&search=&sortBy=final_score&order=desc",
1974
  "host": [
1975
  "{{base_url}}"
1976
  ],
@@ -1979,57 +2435,44 @@
1979
  "v1",
1980
  "admin",
1981
  "events",
1982
- ":event_id",
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": "final_score",
2016
- "description": "Sort field (final_score, created_at, username, full_name)"
2017
  },
2018
  {
2019
  "key": "order",
2020
- "value": "desc",
2021
- "description": "Sort direction (asc / desc)"
 
 
 
 
2022
  }
2023
  ]
2024
  },
2025
- "description": "List all participant results for a specific exam within an event."
2026
  },
2027
  "response": []
2028
  },
2029
  {
2030
- "name": "Results - Edit Result",
2031
  "request": {
2032
- "method": "PUT",
2033
  "header": [
2034
  {
2035
  "key": "Content-Type",
@@ -2044,10 +2487,10 @@
2044
  ],
2045
  "body": {
2046
  "mode": "raw",
2047
- "raw": "{\n \"final_score\": 95.5\n}"
2048
  },
2049
  "url": {
2050
- "raw": "{{base_url}}/api/v1/admin/events/:event_id/exams/:exam_id/results/:result_id",
2051
  "host": [
2052
  "{{base_url}}"
2053
  ],
@@ -2056,44 +2499,35 @@
2056
  "v1",
2057
  "admin",
2058
  "events",
2059
- ":event_id",
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": "Edit the final score of a participant's exam result."
2081
  },
2082
  "response": []
2083
  },
2084
  {
2085
- "name": "Results - Delete Result",
2086
  "request": {
2087
- "method": "DELETE",
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/exams/:exam_id/results/:result_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": "Delete a participant's exam result."
2127
  },
2128
  "response": []
2129
- }
2130
- ]
2131
- },
2132
- {
2133
- "name": "Academy Management",
2134
- "item": [
2135
  {
2136
- "name": "Create Academy",
2137
  "request": {
2138
- "method": "POST",
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/academy/",
2157
  "host": [
2158
  "{{base_url}}"
2159
  ],
@@ -2161,16 +2569,22 @@
2161
  "api",
2162
  "v1",
2163
  "admin",
2164
- "academy",
2165
- ""
 
 
 
 
 
 
2166
  ]
2167
  },
2168
- "description": "Create new academy (admin)"
2169
  },
2170
  "response": []
2171
  },
2172
  {
2173
- "name": "Get Academy Detail",
2174
  "request": {
2175
  "method": "GET",
2176
  "header": [
@@ -2181,7 +2595,7 @@
2181
  }
2182
  ],
2183
  "url": {
2184
- "raw": "{{base_url}}/api/v1/admin/academy/id/:id/detail",
2185
  "host": [
2186
  "{{base_url}}"
2187
  ],
@@ -2189,44 +2603,61 @@
2189
  "api",
2190
  "v1",
2191
  "admin",
2192
- "academy",
2193
- "id",
2194
- ":id",
2195
- "detail"
2196
  ],
2197
  "variable": [
2198
  {
2199
- "key": "id",
2200
- "value": ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2201
  }
2202
  ]
2203
  },
2204
- "description": "Get academy detail by ID (admin)"
2205
  },
2206
  "response": []
2207
  },
2208
  {
2209
- "name": "Update Academy",
2210
  "request": {
2211
- "method": "PUT",
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/academy/id/:id",
2230
  "host": [
2231
  "{{base_url}}"
2232
  ],
@@ -2234,34 +2665,70 @@
2234
  "api",
2235
  "v1",
2236
  "admin",
2237
- "academy",
2238
- "id",
2239
- ":id"
2240
  ],
2241
  "variable": [
2242
  {
2243
- "key": "id",
2244
- "value": ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2245
  }
2246
  ]
2247
  },
2248
- "description": "Update academy (admin)"
2249
  },
2250
  "response": []
2251
  },
2252
  {
2253
- "name": "Delete Academy",
2254
  "request": {
2255
- "method": "DELETE",
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/academy/id/:id",
2265
  "host": [
2266
  "{{base_url}}"
2267
  ],
@@ -2269,43 +2736,34 @@
2269
  "api",
2270
  "v1",
2271
  "admin",
2272
- "academy",
2273
- "id",
2274
- ":id"
2275
  ],
2276
  "variable": [
2277
  {
2278
- "key": "id",
2279
- "value": ""
2280
  }
2281
  ]
2282
  },
2283
- "description": "Delete academy (admin)"
2284
  },
2285
  "response": []
2286
  },
2287
  {
2288
- "name": "Create Material",
2289
  "request": {
2290
- "method": "POST",
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/academy/materials",
2309
  "host": [
2310
  "{{base_url}}"
2311
  ],
@@ -2313,18 +2771,30 @@
2313
  "api",
2314
  "v1",
2315
  "admin",
2316
- "academy",
2317
- "materials"
 
 
 
 
 
 
 
 
 
 
 
 
2318
  ]
2319
  },
2320
- "description": "Create academy material (admin)"
2321
  },
2322
  "response": []
2323
  },
2324
  {
2325
- "name": "Delete Material",
2326
  "request": {
2327
- "method": "DELETE",
2328
  "header": [
2329
  {
2330
  "key": "Authorization",
@@ -2333,7 +2803,7 @@
2333
  }
2334
  ],
2335
  "url": {
2336
- "raw": "{{base_url}}/api/v1/admin/academy/materials/:id",
2337
  "host": [
2338
  "{{base_url}}"
2339
  ],
@@ -2341,43 +2811,61 @@
2341
  "api",
2342
  "v1",
2343
  "admin",
2344
- "academy",
2345
- "materials",
2346
- ":id"
2347
  ],
2348
  "variable": [
2349
  {
2350
- "key": "id",
2351
- "value": ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2352
  }
2353
  ]
2354
  },
2355
- "description": "Delete academy material (admin)"
2356
  },
2357
  "response": []
2358
  },
2359
  {
2360
- "name": "Create Content",
2361
  "request": {
2362
- "method": "POST",
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/academy/contents",
2381
  "host": [
2382
  "{{base_url}}"
2383
  ],
@@ -2385,16 +2873,51 @@
2385
  "api",
2386
  "v1",
2387
  "admin",
2388
- "academy",
2389
- "contents"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2390
  ]
2391
  },
2392
- "description": "Create academy content (admin)"
2393
  },
2394
  "response": []
2395
  },
2396
  {
2397
- "name": "Delete Content",
2398
  "request": {
2399
  "method": "DELETE",
2400
  "header": [
@@ -2405,7 +2928,7 @@
2405
  }
2406
  ],
2407
  "url": {
2408
- "raw": "{{base_url}}/api/v1/admin/academy/contents/:id",
2409
  "host": [
2410
  "{{base_url}}"
2411
  ],
@@ -2413,43 +2936,39 @@
2413
  "api",
2414
  "v1",
2415
  "admin",
2416
- "academy",
2417
- "contents",
2418
- ":id"
 
2419
  ],
2420
  "variable": [
2421
  {
2422
- "key": "id",
2423
- "value": ""
 
 
 
 
2424
  }
2425
  ]
2426
  },
2427
- "description": "Delete academy content (admin)"
2428
  },
2429
  "response": []
2430
  },
2431
  {
2432
- "name": "Assign Account to Academy",
2433
  "request": {
2434
- "method": "POST",
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/academy/assign",
2453
  "host": [
2454
  "{{base_url}}"
2455
  ],
@@ -2457,27 +2976,76 @@
2457
  "api",
2458
  "v1",
2459
  "admin",
2460
- "academy",
2461
- "assign"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2462
  ]
2463
  },
2464
- "description": "Assign user account to academy (admin)"
2465
  },
2466
  "response": []
2467
  },
2468
  {
2469
- "name": "Unassign Account from Academy",
2470
  "request": {
2471
- "method": "DELETE",
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/academy/assign/:id",
2481
  "host": [
2482
  "{{base_url}}"
2483
  ],
@@ -2485,25 +3053,36 @@
2485
  "api",
2486
  "v1",
2487
  "admin",
2488
- "academy",
2489
- "assign",
2490
- ":id"
 
 
 
2491
  ],
2492
  "variable": [
2493
  {
2494
- "key": "id",
2495
- "value": ""
 
 
 
 
 
 
 
 
2496
  }
2497
  ]
2498
  },
2499
- "description": "Unassign user account from academy (admin)"
2500
  },
2501
  "response": []
2502
  },
2503
  {
2504
- "name": "List Academy Assignments",
2505
  "request": {
2506
- "method": "GET",
2507
  "header": [
2508
  {
2509
  "key": "Authorization",
@@ -2512,7 +3091,7 @@
2512
  }
2513
  ],
2514
  "url": {
2515
- "raw": "{{base_url}}/api/v1/admin/academy/assign/:academy_id",
2516
  "host": [
2517
  "{{base_url}}"
2518
  ],
@@ -2520,18 +3099,29 @@
2520
  "api",
2521
  "v1",
2522
  "admin",
2523
- "academy",
2524
- "assign",
2525
- ":academy_id"
 
 
 
2526
  ],
2527
  "variable": [
2528
  {
2529
- "key": "academy_id",
2530
- "value": ""
 
 
 
 
 
 
 
 
2531
  }
2532
  ]
2533
  },
2534
- "description": "List academy assignments by academy ID (admin)"
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/admin/academy/id/{id}/detail [get]
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/admin/academy [post]
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/admin/academy/id/{id} [put]
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/admin/academy/id/{id} [delete]
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/admin/academy/materials [post]
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/admin/academy/materials/{id} [delete]
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/admin/academy/contents [post]
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/admin/academy/contents/{id} [delete]
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/admin/academy/assign [post]
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/admin/academy/assign/{id} [delete]
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/admin/academy/assign/{academy_id} [get]
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, _ := ctx.Get(attrName)
 
 
 
 
 
 
 
 
 
 
 
 
22
  uuidParsed, err := utils.ToUUID(uuidRaw)
23
 
24
  if err != nil {
25
- ResponseJSON(ctx, gin.H{"id": uuidParsed}, uuid.UUID{}, http_error.INVALID_TOKEN)
 
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) ProvideAdminEventController() controllers.AdminEventController {
92
- return c.adminEventController
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
- ProvideAdminEventRepository() repositories.AdminEventRepository
7
- ProvideAdminExamRepository() repositories.AdminExamRepository
8
- ProvideAcademyPaymentRepository() repositories.AcademyPaymentRepository
9
- ProvideAcademyRepository() repositories.AcademyRepository
10
- ProvideAcademyResultRepository() repositories.AcademyResultRepository
11
- ProvideAccountDetailRepository() repositories.AccountDetailRepository
12
- ProvideAccountRepository() repositories.AccountRepository
13
- ProvideEmailVerificationRepository() repositories.EmailVerificationRepository
14
- ProvideEventAssignRepository() repositories.EventAssignRepository
15
- ProvideEventPaymentRepository() repositories.EventPaymentRepository
16
- ProvideEventsRepository() repositories.EventsRepository
17
- ProvideAcademyExamAnswerRepository() repositories.AcademyExamAnswerRepository
18
- ProvideAcademyExamAssignRepository() repositories.AcademyExamAssignRepository
19
- ProvideAcademyExamAttemptRepository() repositories.AcademyExamAttemptRepository
20
- ProvideEventExamAnswerRepository() repositories.EventExamAnswerRepository
21
- ProvideEventExamAssignRepository() repositories.EventExamAssignRepository
22
- ProvideEventExamAttemptRepository() repositories.EventExamAttemptRepository
23
- ProvideEventExamProctoringRepository() repositories.EventExamProctoringRepository
24
- ProvideExamRepository() repositories.ExamRepository
25
- ProvideExternalAuthRepository() repositories.ExternalAuthRepository
26
- ProvideFCMRepository() repositories.FCMRepository
27
- ProvideFileRepository() repositories.FileRepository
28
- ProvideForgotPasswordRepository() repositories.ForgotPasswordRepository
29
- ProvideOptionRepository() repositories.OptionRepository
30
- ProvideProblemSetExamAssignRepository() repositories.ProblemSetExamAssignRepository
31
- ProvideProblemSetRepository() repositories.ProblemSetRepository
32
- ProvideQuestionsRepository() repositories.QuestionsRepository
33
- ProvideRegionRepository() repositories.RegionRepository
34
- ProvideResultRepository() repositories.ResultRepository
35
- }
36
-
37
- type repositoriesProvider struct {
38
- adminEventRepository repositories.AdminEventRepository
39
- adminExamRepository repositories.AdminExamRepository
40
- academyPaymentRepository repositories.AcademyPaymentRepository
41
- academyRepository repositories.AcademyRepository
42
- academyResultRepository repositories.AcademyResultRepository
43
- accountDetailRepository repositories.AccountDetailRepository
44
- accountRepository repositories.AccountRepository
45
- emailVerificationRepository repositories.EmailVerificationRepository
46
- eventAssignRepository repositories.EventAssignRepository
47
- eventPaymentRepository repositories.EventPaymentRepository
48
- eventsRepository repositories.EventsRepository
49
- academyExamAnswerRepository repositories.AcademyExamAnswerRepository
50
- academyExamAssignRepository repositories.AcademyExamAssignRepository
51
- academyExamAttemptRepository repositories.AcademyExamAttemptRepository
52
- eventExamAnswerRepository repositories.EventExamAnswerRepository
53
- eventExamAssignRepository repositories.EventExamAssignRepository
54
- eventExamAttemptRepository repositories.EventExamAttemptRepository
55
- eventExamProctoringRepository repositories.EventExamProctoringRepository
56
- examRepository repositories.ExamRepository
57
- externalAuthRepository repositories.ExternalAuthRepository
58
- fCMRepository repositories.FCMRepository
59
- fileRepository repositories.FileRepository
60
- forgotPasswordRepository repositories.ForgotPasswordRepository
61
- optionRepository repositories.OptionRepository
62
- problemSetExamAssignRepository repositories.ProblemSetExamAssignRepository
63
- problemSetRepository repositories.ProblemSetRepository
64
- questionsRepository repositories.QuestionsRepository
65
- regionRepository repositories.RegionRepository
66
- resultRepository repositories.ResultRepository
67
- }
68
-
69
- func NewRepositoriesProvider(cfg ConfigProvider) RepositoriesProvider {
70
- dbConfig := cfg.ProvideDatabaseConfig()
71
- db := dbConfig.GetInstance()
72
-
73
- adminEventRepository := repositories.NewAdminEventRepository(db)
74
- adminExamRepository := repositories.NewAdminExamRepository(db)
75
- academyPaymentRepository := repositories.NewAcaddemyPaymentRepository(db)
76
- academyRepository := repositories.NewAcademyRepository(db)
77
- academyResultRepository := repositories.NewAcademyResultRepository(db)
78
- accountDetailRepository := repositories.NewAccountDetailRepository(db)
79
- accountRepository := repositories.NewAccountRepository(db)
80
- emailVerificationRepository := repositories.NewEmailVerificationRepository(db)
81
- eventAssignRepository := repositories.NewEventAssignRepository(db)
82
- eventPaymentRepository := repositories.NewEventPaymentRepository(db)
83
- eventsRepository := repositories.NewEventsRepository(db)
84
- academyExamAnswerRepository := repositories.NewAcademyExamAnswerRepository(db)
85
- academyExamAssignRepository := repositories.NewAcademyExamAssignRepository(db)
86
- academyExamAttemptRepository := repositories.NewAcademyExamAttemptRepository(db)
87
- eventExamAnswerRepository := repositories.NewEventExamAnswerRepository(db)
88
- eventExamAssignRepository := repositories.NewEventExamAssignRepository(db)
89
- eventExamAttemptRepository := repositories.NewEventExamAttemptRepository(db)
90
- eventExamProctoringRepository := repositories.NewEventExamProctoringRepository(db)
91
- examRepository := repositories.NewExamRepository(db)
92
- externalAuthRepository := repositories.NewExternalAuthRepository(db)
93
- fCMRepository := repositories.NewFCMRepository(db)
94
- fileRepository := repositories.NewFileRepository(db)
95
- forgotPasswordRepository := repositories.NewForgotPasswordRepository(db)
96
- optionRepository := repositories.NewOptionRepository(db)
97
- problemSetExamAssignRepository := repositories.NewProblemSetExamAssignRepository(db)
98
- problemSetRepository := repositories.NewProblemSetRepository(db)
99
- questionsRepository := repositories.NewQuestionsRepository(db)
100
- regionRepository := repositories.NewRegionRepository(db)
101
- resultRepository := repositories.NewResultRepository(db)
102
-
103
- return &repositoriesProvider{
104
- adminEventRepository: adminEventRepository,
105
- adminExamRepository: adminExamRepository,
106
- academyPaymentRepository: academyPaymentRepository,
107
- academyRepository: academyRepository,
108
- academyResultRepository: academyResultRepository,
109
- accountDetailRepository: accountDetailRepository,
110
- accountRepository: accountRepository,
111
- emailVerificationRepository: emailVerificationRepository,
112
- eventAssignRepository: eventAssignRepository,
113
- eventPaymentRepository: eventPaymentRepository,
114
- eventsRepository: eventsRepository,
115
- academyExamAnswerRepository: academyExamAnswerRepository,
116
- academyExamAssignRepository: academyExamAssignRepository,
117
- academyExamAttemptRepository: academyExamAttemptRepository,
118
- eventExamAnswerRepository: eventExamAnswerRepository,
119
- eventExamAssignRepository: eventExamAssignRepository,
120
- eventExamAttemptRepository: eventExamAttemptRepository,
121
- eventExamProctoringRepository: eventExamProctoringRepository,
122
- examRepository: examRepository,
123
- externalAuthRepository: externalAuthRepository,
124
- fCMRepository: fCMRepository,
125
- fileRepository: fileRepository,
126
- forgotPasswordRepository: forgotPasswordRepository,
127
- optionRepository: optionRepository,
128
- problemSetExamAssignRepository: problemSetExamAssignRepository,
129
- problemSetRepository: problemSetRepository,
130
- questionsRepository: questionsRepository,
131
- regionRepository: regionRepository,
132
- resultRepository: resultRepository,
133
- }
134
- }
135
-
136
- func (r *repositoriesProvider) ProvideAdminEventRepository() repositories.AdminEventRepository {
137
- return r.adminEventRepository
138
- }
139
-
140
- func (r *repositoriesProvider) ProvideAdminExamRepository() repositories.AdminExamRepository {
141
- return r.adminExamRepository
142
- }
143
-
144
- func (r *repositoriesProvider) ProvideAcademyPaymentRepository() repositories.AcademyPaymentRepository {
145
- return r.academyPaymentRepository
146
- }
147
-
148
- func (r *repositoriesProvider) ProvideAcademyRepository() repositories.AcademyRepository {
149
- return r.academyRepository
150
- }
151
-
152
- func (r *repositoriesProvider) ProvideAcademyResultRepository() repositories.AcademyResultRepository {
153
- return r.academyResultRepository
154
- }
155
-
156
- func (r *repositoriesProvider) ProvideAccountDetailRepository() repositories.AccountDetailRepository {
157
- return r.accountDetailRepository
158
- }
159
-
160
- func (r *repositoriesProvider) ProvideAccountRepository() repositories.AccountRepository {
161
- return r.accountRepository
162
- }
163
-
164
- func (r *repositoriesProvider) ProvideEmailVerificationRepository() repositories.EmailVerificationRepository {
165
- return r.emailVerificationRepository
166
- }
167
-
168
- func (r *repositoriesProvider) ProvideEventAssignRepository() repositories.EventAssignRepository {
169
- return r.eventAssignRepository
170
- }
171
-
172
- func (r *repositoriesProvider) ProvideEventPaymentRepository() repositories.EventPaymentRepository {
173
- return r.eventPaymentRepository
174
- }
175
-
176
- func (r *repositoriesProvider) ProvideEventsRepository() repositories.EventsRepository {
177
- return r.eventsRepository
178
- }
179
-
180
- func (r *repositoriesProvider) ProvideAcademyExamAnswerRepository() repositories.AcademyExamAnswerRepository {
181
- return r.academyExamAnswerRepository
182
- }
183
-
184
- func (r *repositoriesProvider) ProvideAcademyExamAssignRepository() repositories.AcademyExamAssignRepository {
185
- return r.academyExamAssignRepository
186
- }
187
-
188
- func (r *repositoriesProvider) ProvideAcademyExamAttemptRepository() repositories.AcademyExamAttemptRepository {
189
- return r.academyExamAttemptRepository
190
- }
191
-
192
- func (r *repositoriesProvider) ProvideEventExamAnswerRepository() repositories.EventExamAnswerRepository {
193
- return r.eventExamAnswerRepository
194
- }
195
-
196
- func (r *repositoriesProvider) ProvideEventExamAssignRepository() repositories.EventExamAssignRepository {
197
- return r.eventExamAssignRepository
198
- }
199
-
200
- func (r *repositoriesProvider) ProvideEventExamAttemptRepository() repositories.EventExamAttemptRepository {
201
- return r.eventExamAttemptRepository
202
- }
203
-
204
- func (r *repositoriesProvider) ProvideEventExamProctoringRepository() repositories.EventExamProctoringRepository {
205
- return r.eventExamProctoringRepository
206
- }
207
-
208
- func (r *repositoriesProvider) ProvideExamRepository() repositories.ExamRepository {
209
- return r.examRepository
210
- }
211
-
212
- func (r *repositoriesProvider) ProvideExternalAuthRepository() repositories.ExternalAuthRepository {
213
- return r.externalAuthRepository
214
- }
215
-
216
- func (r *repositoriesProvider) ProvideFCMRepository() repositories.FCMRepository {
217
- return r.fCMRepository
218
- }
219
-
220
- func (r *repositoriesProvider) ProvideFileRepository() repositories.FileRepository {
221
- return r.fileRepository
222
- }
223
-
224
- func (r *repositoriesProvider) ProvideForgotPasswordRepository() repositories.ForgotPasswordRepository {
225
- return r.forgotPasswordRepository
226
- }
227
-
228
- func (r *repositoriesProvider) ProvideOptionRepository() repositories.OptionRepository {
229
- return r.optionRepository
230
- }
231
-
232
- func (r *repositoriesProvider) ProvideProblemSetExamAssignRepository() repositories.ProblemSetExamAssignRepository {
233
- return r.problemSetExamAssignRepository
234
- }
235
-
236
- func (r *repositoriesProvider) ProvideProblemSetRepository() repositories.ProblemSetRepository {
237
- return r.problemSetRepository
238
- }
239
-
240
- func (r *repositoriesProvider) ProvideQuestionsRepository() repositories.QuestionsRepository {
241
- return r.questionsRepository
242
- }
243
-
244
- func (r *repositoriesProvider) ProvideRegionRepository() repositories.RegionRepository {
245
- return r.regionRepository
246
- }
247
-
248
- func (r *repositoriesProvider) ProvideResultRepository() repositories.ResultRepository {
249
- return r.resultRepository
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
- ProvideAdminEventService() services.AdminEventService
10
- ProvideAdminExamService() services.AdminExamService
11
- ProvideRegionService() services.RegionService
12
- ProvideJWTService() services.JWTService
13
- ProvideAcademyService() services.AcademyService
14
- ProvidePaymentService() services.PaymentService
15
- ProvideUploadService() services.UploadService
16
- ProvideProblemSetService() services.ProblemSetService
17
- ProvideOptionService() services.OptionService
18
- ProvideAccountService() services.AccountService
19
- ProvideForgotPasswordService() services.ForgotPasswordService
20
- ProvideEventService() services.EventService
21
- ProvideAcademyExamService() services.AcademyExamService
22
- ProvideEmailVerificationService() services.EmailVerificationService
23
- ProvideExternalAuthService() services.ExternalAuthService
 
 
24
  ProvideEventExamService() services.EventExamService
25
  ProvideEventExamProctoringService() services.EventExamProctoringService
26
  }
27
-
28
- type servicesProvider struct {
29
- adminEventService services.AdminEventService
30
- adminExamService services.AdminExamService
31
- regionService services.RegionService
32
- jWTService services.JWTService
33
- academyService services.AcademyService
34
- paymentService services.PaymentService
35
- uploadService services.UploadService
36
- problemSetService services.ProblemSetService
37
- optionService services.OptionService
38
- accountService services.AccountService
39
- forgotPasswordService services.ForgotPasswordService
40
- eventService services.EventService
41
- academyExamService services.AcademyExamService
42
- emailVerificationService services.EmailVerificationService
43
- externalAuthService services.ExternalAuthService
 
 
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
- return &servicesProvider{
75
- adminEventService: adminEventService,
76
- adminExamService: adminExamService,
77
- regionService: regionService,
78
- jWTService: jWTService,
79
- academyService: academyService,
80
- paymentService: paymentService,
81
- uploadService: uploadService,
82
- problemSetService: problemSetService,
83
- optionService: optionService,
84
- accountService: accountService,
85
- forgotPasswordService: forgotPasswordService,
86
- eventService: eventService,
87
- academyExamService: academyExamService,
88
- emailVerificationService: emailVerificationService,
89
- externalAuthService: externalAuthService,
 
 
 
 
90
  eventExamService: eventExamService,
91
  eventExamProctoringService: eventExamProctoringService,
92
  }
93
  }
94
-
95
- func (s *servicesProvider) ProvideAdminEventService() services.AdminEventService {
96
- return s.adminEventService
97
- }
98
-
99
- func (s *servicesProvider) ProvideAdminExamService() services.AdminExamService {
100
- return s.adminExamService
101
- }
102
-
103
- func (s *servicesProvider) ProvideRegionService() services.RegionService {
104
- return s.regionService
105
- }
106
-
107
- func (s *servicesProvider) ProvideJWTService() services.JWTService {
108
- return s.jWTService
109
- }
110
-
111
- func (s *servicesProvider) ProvideAcademyService() services.AcademyService {
112
- return s.academyService
113
- }
114
-
115
- func (s *servicesProvider) ProvidePaymentService() services.PaymentService {
116
- return s.paymentService
117
- }
118
-
119
- func (s *servicesProvider) ProvideUploadService() services.UploadService {
120
- return s.uploadService
121
- }
122
-
123
- func (s *servicesProvider) ProvideProblemSetService() services.ProblemSetService {
124
- return s.problemSetService
125
- }
126
-
127
- func (s *servicesProvider) ProvideOptionService() services.OptionService {
128
- return s.optionService
129
- }
130
-
131
- func (s *servicesProvider) ProvideAccountService() services.AccountService {
132
- return s.accountService
133
- }
134
-
135
- func (s *servicesProvider) ProvideForgotPasswordService() services.ForgotPasswordService {
136
- return s.forgotPasswordService
137
- }
138
-
139
- func (s *servicesProvider) ProvideEventService() services.EventService {
140
- return s.eventService
141
- }
142
-
143
- func (s *servicesProvider) ProvideAcademyExamService() services.AcademyExamService {
144
- return s.academyExamService
145
- }
146
-
147
- func (s *servicesProvider) ProvideEmailVerificationService() services.EmailVerificationService {
148
- return s.emailVerificationService
149
- }
150
-
151
- func (s *servicesProvider) ProvideExternalAuthService() services.ExternalAuthService {
152
- return s.externalAuthService
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
+ }