Added persistent prompt to student progress report

This commit is contained in:
ivan-pelly
2026-04-10 15:31:56 -07:00
parent d4a580ffae
commit b287276ec0
21 changed files with 606 additions and 11 deletions
@@ -0,0 +1,191 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WinStudentGoalTracker.Models;
using WinStudentGoalTracker.Models.ResponseTypes;
using WinStudentGoalTracker.BaseClasses;
using WinStudentGoalTracker.DataAccess;
namespace WinStudentGoalTracker.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ReportPromptController : BaseController
{
// ************************** Constructor **************************
private readonly ReportPromptRepository _reportPromptRepository;
public ReportPromptController()
{
_reportPromptRepository = new();
}
// ************************ Public Methods *************************
[HttpGet]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<IEnumerable<ReportPromptResponse>>), StatusCodes.Status200OK)]
public async Task<ActionResult<ResponseResult<IEnumerable<ReportPromptResponse>>>> GetAll()
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var prompts = await _reportPromptRepository.GetAllAsync();
return Ok(new ResponseResult<IEnumerable<ReportPromptResponse>>
{
Success = true,
Message = "Report prompts retrieved successfully.",
Data = prompts
});
}
[HttpGet("{idReportPrompt:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<ReportPromptResponse>>> GetById(Guid idReportPrompt)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var prompt = await _reportPromptRepository.GetByIdAsync(idReportPrompt);
if (prompt is null)
{
return NotFound(new ResponseResult<ReportPromptResponse>
{
Success = false,
Message = "Report prompt not found."
});
}
return Ok(new ResponseResult<ReportPromptResponse>
{
Success = true,
Message = "Report prompt retrieved successfully.",
Data = prompt
});
}
// *****************************************************************
// Returns the report prompt for the given reportname scoped to
// the authenticated user's program.
// *****************************************************************
[HttpGet("by-name/{reportname}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<ReportPromptResponse>>> GetByReportname(string reportname)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var prompt = await _reportPromptRepository.GetByReportnameAsync(reportname, programId);
if (prompt is null)
{
return NotFound(new ResponseResult<ReportPromptResponse>
{
Success = false,
Message = "Report prompt not found."
});
}
return Ok(new ResponseResult<ReportPromptResponse>
{
Success = true,
Message = "Report prompt retrieved successfully.",
Data = prompt
});
}
[HttpPost]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ResponseResult<ReportPromptResponse>), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<ResponseResult<ReportPromptResponse>>> Create([FromBody] CreateReportPromptDto dto)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
// Scope the new prompt to the authenticated user's program.
dto.ProgramId = programId.ToString();
var created = await _reportPromptRepository.InsertAsync(dto);
if (created is null)
{
return BadRequest(new ResponseResult<ReportPromptResponse>
{
Success = false,
Message = "Unable to create report prompt."
});
}
return StatusCode(StatusCodes.Status201Created, new ResponseResult<ReportPromptResponse>
{
Success = true,
Message = "Report prompt created successfully.",
Data = created
});
}
[HttpPut("{idReportPrompt:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<object>>> Update(Guid idReportPrompt, [FromBody] UpdateReportPromptDto dto)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var updated = await _reportPromptRepository.UpdateAsync(idReportPrompt, dto);
return Ok(new ResponseResult<object>
{
Success = true,
Message = updated ? "Report prompt updated successfully." : "No changes were applied."
});
}
[HttpDelete("{idReportPrompt:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.ProgramAdmin},{UserRoles.SuperAdmin}")]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<object>>> Delete(Guid idReportPrompt)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var deleted = await _reportPromptRepository.DeleteAsync(idReportPrompt);
if (!deleted)
{
return NotFound(new ResponseResult<object>
{
Success = false,
Message = "Report prompt not found."
});
}
return Ok(new ResponseResult<object>
{
Success = true,
Message = "Report prompt deleted."
});
}
}
@@ -0,0 +1,8 @@
namespace WinStudentGoalTracker.DataAccess;
public class CreateReportPromptDto
{
public string? ProgramId { get; set; }
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -0,0 +1,7 @@
namespace WinStudentGoalTracker.DataAccess;
public class UpdateReportPromptDto
{
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -0,0 +1,9 @@
namespace WinStudentGoalTracker.DataAccess;
public class dbReportPrompt
{
public required Guid IdReportPrompt { get; set; }
public Guid? IdProgram { get; set; }
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}
@@ -0,0 +1,105 @@
using System.Data;
using Dapper;
using MySql.Data.MySqlClient;
using WinStudentGoalTracker.Models;
namespace WinStudentGoalTracker.DataAccess;
public class ReportPromptRepository
{
private IDbConnection Connection => new MySqlConnection(DatabaseManager.ConnectionString);
// *****************************************************************
// Returns all report prompts.
// *****************************************************************
public async Task<IEnumerable<ReportPromptResponse>> GetAllAsync()
{
using var db = Connection;
return await db.QueryAsync<ReportPromptResponse>(
"sp_ReportPrompt_GetAll",
commandType: CommandType.StoredProcedure);
}
// *****************************************************************
// Returns a single report prompt by its ID, or null if not found.
// *****************************************************************
public async Task<ReportPromptResponse?> GetByIdAsync(Guid idReportPrompt)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<ReportPromptResponse>(
"sp_ReportPrompt_GetById",
new { p_id_report_prompt = idReportPrompt.ToString() },
commandType: CommandType.StoredProcedure);
}
// *****************************************************************
// Returns a single report prompt by its reportname and program,
// or null if not found.
// *****************************************************************
public async Task<ReportPromptResponse?> GetByReportnameAsync(string reportname, Guid programId)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<ReportPromptResponse>(
"sp_ReportPrompt_GetByReportname",
new
{
p_reportname = reportname,
p_id_program = programId.ToString()
},
commandType: CommandType.StoredProcedure);
}
// *****************************************************************
// Inserts a new report prompt and returns the created record.
// *****************************************************************
public async Task<ReportPromptResponse?> InsertAsync(CreateReportPromptDto dto)
{
var newId = Guid.NewGuid();
using var db = Connection;
await db.ExecuteAsync(
"sp_ReportPrompt_Insert",
new
{
p_id_report_prompt = newId.ToString(),
p_id_program = dto.ProgramId,
p_prompt = dto.Prompt,
p_reportname = dto.Reportname
},
commandType: CommandType.StoredProcedure);
return await GetByIdAsync(newId);
}
// *****************************************************************
// Updates an existing report prompt. Returns true if a row was
// affected, false otherwise.
// *****************************************************************
public async Task<bool> UpdateAsync(Guid idReportPrompt, UpdateReportPromptDto dto)
{
using var db = Connection;
var rowsAffected = await db.ExecuteScalarAsync<int>(
"sp_ReportPrompt_Update",
new
{
p_id_report_prompt = idReportPrompt.ToString(),
p_prompt = dto.Prompt,
p_reportname = dto.Reportname
},
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
}
// *****************************************************************
// Deletes a report prompt by its ID. Returns true if a row was
// affected, false otherwise.
// *****************************************************************
public async Task<bool> DeleteAsync(Guid idReportPrompt)
{
using var db = Connection;
var rowsAffected = await db.ExecuteScalarAsync<int>(
"sp_ReportPrompt_Delete",
new { p_id_report_prompt = idReportPrompt.ToString() },
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
}
}
@@ -0,0 +1,9 @@
namespace WinStudentGoalTracker.Models;
public class ReportPromptResponse
{
public Guid ReportPromptId { get; set; }
public Guid? ProgramId { get; set; }
public string? Prompt { get; set; }
public string? Reportname { get; set; }
}