From 0fb4effd26ec3f2be1dbda1ae73bf52746f9e387 Mon Sep 17 00:00:00 2001 From: Oliver Pelly Date: Fri, 27 Feb 2026 19:17:40 -0800 Subject: [PATCH] Latest --- api/src/Controllers/StudentController.cs | 18 +++++- .../Models/DatabaseObjects/dbStudent.cs | 1 - .../Models/DatabaseObjects/dbUserStudent.cs | 9 +++ .../Repositories/StudentRepository.cs | 35 ++++-------- .../Models/ResponseTypes/ResponseResult.cs | 57 ++++++++++++++++++- api/src/Services/PermissionService.cs | 2 +- 6 files changed, 94 insertions(+), 28 deletions(-) create mode 100644 api/src/DataAccess/Models/DatabaseObjects/dbUserStudent.cs diff --git a/api/src/Controllers/StudentController.cs b/api/src/Controllers/StudentController.cs index fbe88c5..d118ab7 100644 --- a/api/src/Controllers/StudentController.cs +++ b/api/src/Controllers/StudentController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using WinStudentGoalTracker.Models; using WinStudentGoalTracker.BaseClasses; using WinStudentGoalTracker.DataAccess; +using WinStudentGoalTracker.Services; namespace WinStudentGoalTracker.Controllers; @@ -31,6 +32,7 @@ public class StudentController : BaseController return Ok(new ResponseResult> { Success = true, + Message = "Students retrieved successfully.", Data = response }); } @@ -52,12 +54,13 @@ public class StudentController : BaseController return error; } - var students = await _studentRepository.GetStudentsByProgramAsync(idProgram); + var students = await _studentRepository.GetMyStudentsAsync(userId, idProgram, role); var response = students.Select(StudentResponse.FromDatabaseModel); return Ok(new ResponseResult> { Success = true, + Message = "Students retrieved successfully.", Data = response }); } @@ -91,6 +94,7 @@ public class StudentController : BaseController return Ok(new ResponseResult { Success = true, + Message = "Student retrieved successfully.", Data = StudentResponse.FromDatabaseModel(student) }); } @@ -108,6 +112,15 @@ public class StudentController : BaseController return error; } + if (!PermissionService.IsAllowed(role, EntityType.Student, PermissionAction.Create)) + { + return BadRequest(new ResponseResult + { + Success = false, + Message = "Unable to create student." + }); + } + var newStudentId = Guid.NewGuid(); var created = await _studentRepository.InsertAsync(newStudentData, newStudentId, programId, userId); if (created is null) @@ -123,6 +136,7 @@ public class StudentController : BaseController return CreatedAtAction(nameof(GetById), new { idStudent = response.IdStudent }, new ResponseResult { Success = true, + Message = "Student created successfully.", Data = response }); } @@ -164,7 +178,7 @@ public class StudentController : BaseController return Ok(new ResponseResult { Success = true, - Message = updated ? null : "No changes were applied.", + Message = updated ? "Changes applied successfully." : "No changes were applied.", Data = StudentResponse.FromDatabaseModel(refreshed) }); } diff --git a/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs b/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs index f2b5ab9..0f87a9b 100644 --- a/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs +++ b/api/src/DataAccess/Models/DatabaseObjects/dbStudent.cs @@ -4,7 +4,6 @@ public class dbStudent { public required Guid IdStudent { get; set; } public Guid? IdProgram { get; set; } - public Guid PrimaryTeacherId { get; set; } public string? Identifier { get; set; } public int? ProgramYear { get; set; } public DateTime? EnrollmentDate { get; set; } diff --git a/api/src/DataAccess/Models/DatabaseObjects/dbUserStudent.cs b/api/src/DataAccess/Models/DatabaseObjects/dbUserStudent.cs new file mode 100644 index 0000000..a3b325e --- /dev/null +++ b/api/src/DataAccess/Models/DatabaseObjects/dbUserStudent.cs @@ -0,0 +1,9 @@ +namespace WinStudentGoalTracker.DataAccess; + +public class dbUserStudent +{ + public required Guid IdUserStudent { get; set; } + public Guid? IdUser { get; set; } + public Guid? IdStudent { get; set; } + public bool? IsPrimary { get; set; } +} diff --git a/api/src/DataAccess/Repositories/StudentRepository.cs b/api/src/DataAccess/Repositories/StudentRepository.cs index f1a6e5d..80b261d 100644 --- a/api/src/DataAccess/Repositories/StudentRepository.cs +++ b/api/src/DataAccess/Repositories/StudentRepository.cs @@ -2,6 +2,7 @@ using System.Data; using Dapper; using MySql.Data.MySqlClient; using WinStudentGoalTracker.Models; +using WinStudentGoalTracker.Services; namespace WinStudentGoalTracker.DataAccess; @@ -10,33 +11,21 @@ public class StudentRepository private IDbConnection Connection => new MySqlConnection(DatabaseManager.ConnectionString); public async Task> GetMyStudentsAsync(Guid userId, Guid programId, string role) - { - return role switch - { - UserRoles.Teacher or UserRoles.ProgramAdmin => - await GetStudentsByProgramAsync(programId), - UserRoles.Paraeducator => - await GetAssignedStudentsAsync(userId, programId), - _ => Enumerable.Empty() - }; - } - - public async Task> GetStudentsByProgramAsync(Guid programId) { using var db = Connection; - return await db.QueryAsync( - "sp_Student_GetByProgram", - new { p_id_program = programId.ToString() }, + using var multi = await db.QueryMultipleAsync( + "sp_Student_GetWithAssignments", + new { p_id_program = programId.ToString(), p_id_user = userId.ToString() }, commandType: CommandType.StoredProcedure); - } - private async Task> GetAssignedStudentsAsync(Guid userId, Guid programId) - { - using var db = Connection; - return await db.QueryAsync( - "sp_Student_GetByUserAndProgram", - new { p_id_user = userId.ToString(), p_id_program = programId.ToString() }, - commandType: CommandType.StoredProcedure); + var students = await multi.ReadAsync(); + var assignments = await multi.ReadAsync(); + + var myStudents = students.Where(s => + PermissionService.IsAllowed(role, EntityType.Student, PermissionAction.Read , assignments.Any(a => a.IdStudent == s.IdStudent && a.IdUser == userId)) + ); + + return myStudents; } public async Task GetByIdAsync(Guid idStudent) diff --git a/api/src/Models/ResponseTypes/ResponseResult.cs b/api/src/Models/ResponseTypes/ResponseResult.cs index c6c3fa2..b0c9f01 100644 --- a/api/src/Models/ResponseTypes/ResponseResult.cs +++ b/api/src/Models/ResponseTypes/ResponseResult.cs @@ -3,6 +3,61 @@ namespace WinStudentGoalTracker.Models; public class ResponseResult { public bool Success { get; set; } - public string? Message { get; set; } + public required string Message { get; set; } public T? Data { get; set; } + + + public static ResponseResult SuccessMessage(string message) + { + return new ResponseResult + { + Success = true, + Message = message, + Data = null + }; + } + + public static ResponseResult FailureMessage(string message) + { + return new ResponseResult + { + Success = false, + Message = message, + Data = null + }; + } + + } + +public class EmptyResponse { } + + +public class ResponseResult +{ + public bool Success { get; set; } + public required string Message { get; set; } + public EmptyResponse? Data { get; set; } = new EmptyResponse(); + + public static ResponseResult SuccessMessage(string message) + { + return new ResponseResult + { + Success = true, + Message = message, + Data = new EmptyResponse() + }; + } + + public static ResponseResult FailureMessage(string message) + { + return new ResponseResult + { + Success = false, + Message = message, + Data = new EmptyResponse() + }; + } +} + + diff --git a/api/src/Services/PermissionService.cs b/api/src/Services/PermissionService.cs index b8b5e0f..1558878 100644 --- a/api/src/Services/PermissionService.cs +++ b/api/src/Services/PermissionService.cs @@ -14,7 +14,7 @@ public class PermissionService /// Whether the resource belongs to the requesting user. /// For Create actions this parameter is ignored. /// True if the action is permitted, false otherwise. - public bool IsAllowed(string role, string entity, string action, bool isMine = true) + public static bool IsAllowed(string role, string entity, string action, bool isMine = true) { var rule = PermissionMatrix.GetRule(role, entity, action);