Added Goals fields

This commit is contained in:
ivan-pelly
2026-03-15 09:35:58 -07:00
parent 242b1bce27
commit 53d0539d28
66 changed files with 1322 additions and 329 deletions
+66 -4
View File
@@ -294,8 +294,10 @@ public class StudentController : BaseController
});
}
var created = await _studentRepository.AddProgressEventAsync(userId, dto);
if (!created)
var newId = Guid.NewGuid();
var created = await _studentRepository.SaveProgressEventAsync(
newId, dto.GoalId, userId, dto.Content, isNew: true, dto.BenchmarkIds);
if (created is null)
{
return BadRequest(new ResponseResult
{
@@ -304,10 +306,70 @@ public class StudentController : BaseController
});
}
return StatusCode(StatusCodes.Status201Created, new ResponseResult
return StatusCode(StatusCodes.Status201Created, new ResponseResult<object>
{
Success = true,
Message = "Progress event added successfully."
Message = "Progress event added successfully.",
Data = new { progressEventId = created.Value }
});
}
[HttpPut("{idStudent:guid}/progress-events/{idProgressEvent:guid}")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.Paraeducator},{UserRoles.ProgramAdmin}")]
[ProducesResponseType(typeof(ResponseResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult>> UpdateProgressEvent(
Guid idStudent, Guid idProgressEvent, [FromBody] UpdateProgressEventDto dto)
{
var (userId, email, programId, role, error) = GetProgramUserFromClaims();
if (error is not null)
{
return error;
}
var students = await _studentRepository.GetMyStudentsAsync(userId, programId, role);
if (!students.Select(s => s.StudentId).Contains(idStudent))
{
return NotFound(new ResponseResult
{
Success = false,
Message = "Student not found."
});
}
try
{
await _studentRepository.SaveProgressEventAsync(
idProgressEvent, Guid.Empty, userId, dto.Content, isNew: false, dto.BenchmarkIds);
return Ok(new ResponseResult
{
Success = true,
Message = "Progress event updated successfully."
});
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, new ResponseResult
{
Success = false,
Message = $"[DIAG] {ex.GetType().Name}: {ex.Message} | Inner: {ex.InnerException?.Message}"
});
}
}
[HttpGet("progress-events/{idProgressEvent:guid}/benchmarks")]
[Authorize(Roles = $"{UserRoles.Teacher},{UserRoles.Paraeducator},{UserRoles.ProgramAdmin}")]
[ProducesResponseType(typeof(ResponseResult<List<Guid>>), StatusCodes.Status200OK)]
public async Task<ActionResult<ResponseResult<List<Guid>>>> GetProgressEventBenchmarks(Guid idProgressEvent)
{
var benchmarkIds = await _studentRepository.GetBenchmarkIdsForEventAsync(idProgressEvent);
return Ok(new ResponseResult<List<Guid>>
{
Success = true,
Message = "Benchmark associations retrieved.",
Data = benchmarkIds
});
}
@@ -5,4 +5,5 @@ public class AddProgressEventDto
public Guid GoalId { get; set; }
public string? Content { get; set; }
public bool IsSensitive { get; set; }
public List<Guid>? BenchmarkIds { get; set; }
}
@@ -6,4 +6,5 @@ public class CreateGoalDto
public string? Category { get; set; }
public string? Baseline { get; set; }
public Guid? GoalParentId { get; set; }
public DateTime? TargetCompletionDate { get; set; }
}
@@ -5,4 +5,8 @@ public class UpdateGoalDto
public string? Description { get; set; }
public string? Category { get; set; }
public string? Baseline { get; set; }
public DateTime? TargetCompletionDate { get; set; }
public DateTime? CloseDate { get; set; }
public bool? Achieved { get; set; }
public string? CloseNotes { get; set; }
}
@@ -0,0 +1,7 @@
namespace WinStudentGoalTracker.DataAccess;
public class UpdateProgressEventDto
{
public string? Content { get; set; }
public List<Guid>? BenchmarkIds { get; set; }
}
@@ -8,6 +8,10 @@ public class dbStudentGoalRow
public string? Description { get; set; }
public string? Category { get; set; }
public string? Baseline { get; set; }
public DateTime? TargetCompletionDate { get; set; }
public DateTime? CloseDate { get; set; }
public bool? Achieved { get; set; }
public string? CloseNotes { get; set; }
public int ProgressEventCount { get; set; }
public int BenchmarkCount { get; set; }
}
@@ -84,21 +84,49 @@ public class StudentRepository
return rowsAffected > 0;
}
public async Task<bool> AddProgressEventAsync(Guid userId, AddProgressEventDto dto)
// *****************************************************************
// Saves a progress event (insert or update) and syncs benchmark
// associations in a single stored procedure call.
// *****************************************************************
public async Task<Guid?> SaveProgressEventAsync(
Guid progressEventId, Guid goalId, Guid userId,
string? content, bool isNew, List<Guid>? benchmarkIds)
{
var idsCsv = benchmarkIds is { Count: > 0 }
? string.Join(",", benchmarkIds.Select(id => id.ToString()))
: null;
using var db = Connection;
var row = await db.QuerySingleOrDefaultAsync(
"sp_ProgressEvent_Insert",
var row = await db.QuerySingleOrDefaultAsync<dynamic>(
"sp_ProgressEvent_Save",
new
{
p_id_progress_event = Guid.NewGuid().ToString(),
p_id_goal = dto.GoalId.ToString(),
p_id_progress_event = progressEventId.ToString(),
p_id_goal = goalId.ToString(),
p_id_user_created = userId.ToString(),
p_content = dto.Content,
p_is_sensitive = dto.IsSensitive ? 1 : 0
p_content = content,
p_is_sensitive = 0,
p_is_new = isNew ? 1 : 0,
p_benchmark_ids = idsCsv
},
commandType: CommandType.StoredProcedure);
return row is not null;
if (row is null) return null;
return row.progressEventId is Guid g ? g : Guid.Parse((string)row.progressEventId);
}
// *****************************************************************
// Returns the benchmark IDs associated with a progress event.
// *****************************************************************
public async Task<List<Guid>> GetBenchmarkIdsForEventAsync(Guid progressEventId)
{
using var db = Connection;
var rows = await db.QueryAsync<dynamic>(
"sp_ProgressEventBenchmark_GetByEventId",
new { p_id_progress_event = progressEventId.ToString() },
commandType: CommandType.StoredProcedure);
return rows.Select(r => r.benchmarkId is Guid g ? g : Guid.Parse((string)r.benchmarkId)).ToList();
}
public async Task<Guid?> GetStudentIdForGoalAsync(Guid idGoal)
@@ -146,7 +174,8 @@ public class StudentRepository
p_id_user_created = userId.ToString(),
p_description = dto.Description,
p_category = dto.Category,
p_baseline = dto.Baseline
p_baseline = dto.Baseline,
p_target_completion_date = dto.TargetCompletionDate
},
commandType: CommandType.StoredProcedure);
@@ -159,6 +188,7 @@ public class StudentRepository
Description = dto.Description,
Category = dto.Category,
Baseline = dto.Baseline,
TargetCompletionDate = dto.TargetCompletionDate,
ProgressEventCount = 0
};
}
@@ -194,6 +224,10 @@ public class StudentRepository
Description = r.Description,
Category = r.Category,
Baseline = r.Baseline,
TargetCompletionDate = r.TargetCompletionDate,
CloseDate = r.CloseDate,
Achieved = r.Achieved,
CloseNotes = r.CloseNotes,
ProgressEventCount = r.ProgressEventCount,
BenchmarkCount = r.BenchmarkCount
}).ToList()
@@ -216,7 +250,11 @@ public class StudentRepository
p_id_user_created = (string?)null,
p_description = dto.Description,
p_category = dto.Category,
p_baseline = dto.Baseline
p_baseline = dto.Baseline,
p_target_completion_date = dto.TargetCompletionDate,
p_close_date = dto.CloseDate,
p_achieved = dto.Achieved,
p_close_notes = dto.CloseNotes
},
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
@@ -7,6 +7,10 @@ public class StudentGoalItem
public string? Description { get; set; }
public string? Category { get; set; }
public string? Baseline { get; set; }
public DateTime? TargetCompletionDate { get; set; }
public DateTime? CloseDate { get; set; }
public bool? Achieved { get; set; }
public string? CloseNotes { get; set; }
public int ProgressEventCount { get; set; }
public int BenchmarkCount { get; set; }
}
@@ -8,4 +8,5 @@ public class StudentResponse
public DateTime? LastEntryDate { get; set; }
public int GoalCount { get; set; }
public int ProgressEventCount { get; set; }
public int BenchmarkCount { get; set; }
}