| 1 | using System.Security.Claims;
|
|---|
| 2 | using iknow_api.DTOs;
|
|---|
| 3 | using iknow_api.Services;
|
|---|
| 4 | using Microsoft.AspNetCore.Authorization;
|
|---|
| 5 | using Microsoft.AspNetCore.Mvc;
|
|---|
| 6 |
|
|---|
| 7 | namespace iknow_api.Controllers
|
|---|
| 8 | {
|
|---|
| 9 | /// <summary>
|
|---|
| 10 | /// UC012 subjects, UC013 active semesters, UC014 professor assignments.
|
|---|
| 11 | /// Every action requires the admin role, checked against the validated token.
|
|---|
| 12 | /// </summary>
|
|---|
| 13 | [ApiController]
|
|---|
| 14 | [Route("api/[controller]")]
|
|---|
| 15 | [Authorize]
|
|---|
| 16 | public class AdminController : ControllerBase
|
|---|
| 17 | {
|
|---|
| 18 | private readonly IAdminService _adminService;
|
|---|
| 19 |
|
|---|
| 20 | public AdminController(IAdminService adminService)
|
|---|
| 21 | {
|
|---|
| 22 | _adminService = adminService;
|
|---|
| 23 | }
|
|---|
| 24 |
|
|---|
| 25 | // ---------- UC012 ----------
|
|---|
| 26 |
|
|---|
| 27 | [HttpGet("subjects")]
|
|---|
| 28 | public async Task<IActionResult> GetSubjects() =>
|
|---|
| 29 | RequireAdmin(out var error) ? Ok(await _adminService.GetSubjectsAsync()) : error;
|
|---|
| 30 |
|
|---|
| 31 | [HttpPost("subjects")]
|
|---|
| 32 | public async Task<IActionResult> CreateSubject([FromBody] SubjectWriteDto request) =>
|
|---|
| 33 | RequireAdmin(out var error) ? Result(await _adminService.CreateSubjectAsync(request)) : error;
|
|---|
| 34 |
|
|---|
| 35 | [HttpPut("subjects/{id:int}")]
|
|---|
| 36 | public async Task<IActionResult> UpdateSubject(int id, [FromBody] SubjectWriteDto request) =>
|
|---|
| 37 | RequireAdmin(out var error) ? Result(await _adminService.UpdateSubjectAsync(id, request)) : error;
|
|---|
| 38 |
|
|---|
| 39 | [HttpDelete("subjects/{id:int}")]
|
|---|
| 40 | public async Task<IActionResult> DeleteSubject(int id) =>
|
|---|
| 41 | RequireAdmin(out var error) ? Result(await _adminService.DeleteSubjectAsync(id)) : error;
|
|---|
| 42 |
|
|---|
| 43 | [HttpPost("subjects/{id:int}/majors")]
|
|---|
| 44 | public async Task<IActionResult> LinkMajor(int id, [FromBody] MajorLinkDto request) =>
|
|---|
| 45 | RequireAdmin(out var error) ? Result(await _adminService.LinkMajorAsync(id, request)) : error;
|
|---|
| 46 |
|
|---|
| 47 | [HttpDelete("subjects/{id:int}/majors/{majorId:int}")]
|
|---|
| 48 | public async Task<IActionResult> UnlinkMajor(int id, int majorId) =>
|
|---|
| 49 | RequireAdmin(out var error) ? Result(await _adminService.UnlinkMajorAsync(id, majorId)) : error;
|
|---|
| 50 |
|
|---|
| 51 | [HttpPost("subjects/{id:int}/prerequisites")]
|
|---|
| 52 | public async Task<IActionResult> AddPrerequisite(int id, [FromBody] PrerequisiteDto request) =>
|
|---|
| 53 | RequireAdmin(out var error) ? Result(await _adminService.AddPrerequisiteAsync(id, request)) : error;
|
|---|
| 54 |
|
|---|
| 55 | [HttpDelete("subjects/{id:int}/prerequisites/{dependencyId:int}")]
|
|---|
| 56 | public async Task<IActionResult> RemovePrerequisite(int id, int dependencyId) =>
|
|---|
| 57 | RequireAdmin(out var error) ? Result(await _adminService.RemovePrerequisiteAsync(id, dependencyId)) : error;
|
|---|
| 58 |
|
|---|
| 59 | // ---------- UC013 ----------
|
|---|
| 60 |
|
|---|
| 61 | [HttpGet("semesters")]
|
|---|
| 62 | public async Task<IActionResult> GetSemesters() =>
|
|---|
| 63 | RequireAdmin(out var error) ? Ok(await _adminService.GetSemestersAsync()) : error;
|
|---|
| 64 |
|
|---|
| 65 | [HttpPost("semesters")]
|
|---|
| 66 | public async Task<IActionResult> CreateSemester([FromBody] SemesterWriteDto request) =>
|
|---|
| 67 | RequireAdmin(out var error) ? Result(await _adminService.CreateSemesterAsync(request)) : error;
|
|---|
| 68 |
|
|---|
| 69 | // ---------- UC014 ----------
|
|---|
| 70 |
|
|---|
| 71 | [HttpGet("schedule/{semesterId:int}")]
|
|---|
| 72 | public async Task<IActionResult> GetSchedule(int semesterId)
|
|---|
| 73 | {
|
|---|
| 74 | if (!RequireAdmin(out var error)) return error;
|
|---|
| 75 |
|
|---|
| 76 | var schedule = await _adminService.GetScheduleAsync(semesterId);
|
|---|
| 77 | return schedule is null
|
|---|
| 78 | ? NotFound(new AdminResultDto { Ok = false, Message = "Semester not found." })
|
|---|
| 79 | : Ok(schedule);
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | [HttpPost("schedule")]
|
|---|
| 83 | public async Task<IActionResult> Assign([FromBody] ScheduleWriteDto request) =>
|
|---|
| 84 | RequireAdmin(out var error) ? Result(await _adminService.AssignAsync(request)) : error;
|
|---|
| 85 |
|
|---|
| 86 | [HttpDelete("schedule")]
|
|---|
| 87 | public async Task<IActionResult> Unassign([FromBody] ScheduleWriteDto request) =>
|
|---|
| 88 | RequireAdmin(out var error) ? Result(await _adminService.UnassignAsync(request)) : error;
|
|---|
| 89 |
|
|---|
| 90 | // ---------- shared ----------
|
|---|
| 91 |
|
|---|
| 92 | [HttpGet("majors")]
|
|---|
| 93 | public async Task<IActionResult> GetMajors() =>
|
|---|
| 94 | RequireAdmin(out var error) ? Ok(await _adminService.GetMajorsAsync()) : error;
|
|---|
| 95 |
|
|---|
| 96 | private IActionResult Result(AdminResultDto result) =>
|
|---|
| 97 | result.Ok ? Ok(result) : BadRequest(result);
|
|---|
| 98 |
|
|---|
| 99 | /// <summary>
|
|---|
| 100 | /// The role comes from the validated token, so it cannot be set by the caller.
|
|---|
| 101 | /// </summary>
|
|---|
| 102 | private bool RequireAdmin(out IActionResult error)
|
|---|
| 103 | {
|
|---|
| 104 | var role = User.FindFirst(ClaimTypes.Role)?.Value ?? User.FindFirst("role")?.Value;
|
|---|
| 105 | if (!string.Equals(role, nameof(Models.UserRole.Admin), StringComparison.OrdinalIgnoreCase))
|
|---|
| 106 | {
|
|---|
| 107 | error = StatusCode(403, new AdminResultDto
|
|---|
| 108 | {
|
|---|
| 109 | Ok = false,
|
|---|
| 110 | Message = "This endpoint is for administrators."
|
|---|
| 111 | });
|
|---|
| 112 | return false;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | error = Ok();
|
|---|
| 116 | return true;
|
|---|
| 117 | }
|
|---|
| 118 | }
|
|---|
| 119 | }
|
|---|