Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions BackEnd/Domain/Domain.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
6 changes: 6 additions & 0 deletions BackEnd/Domain/Models/DashboardSummary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Domain.Models;

public class DashboardSummary
{
public List<SubjectAverage> SubjectAverages { get; set; } = new();
}
7 changes: 7 additions & 0 deletions BackEnd/Domain/Models/Student.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Domain.Models;

public class Student
{
public int UserId { get; set; }
public string Name => $"Student {UserId}";
}
24 changes: 24 additions & 0 deletions BackEnd/Domain/Models/StudentData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;

namespace Domain.Models;

public class StudentData
{
public int UserId { get; set; }
public required string Name { get; set; }
public List<StudentSubjectAverage> SubjectAverages { get; set; } = new();
public IList<StudentExerciseResult> Exercises { get; set; } = new List<StudentExerciseResult>();
}

public class StudentExerciseResult
{
public Subject Subject { get; set; }
public required string SubjectName { get; set; }
public long ExerciseId { get; set; }
public required string ExerciseName { get; set; }
public bool Correct { get; set; }
public decimal Difficulty { get; set; }
public decimal Progress { get; set; }
public DateTime SubmitDateTime { get; set; }
}
14 changes: 14 additions & 0 deletions BackEnd/Domain/Models/StudentListItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Domain.Models;

public class StudentSubjectAverage
{
public Subject Subject { get; set; }
public decimal Average { get; set; }
}

public class StudentListItem
{
public int UserId { get; set; }
public string Name { get; set; } = string.Empty;
public List<StudentSubjectAverage> SubjectAverages { get; set; } = new();
}
33 changes: 33 additions & 0 deletions BackEnd/Domain/Models/Subject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace Domain.Models;

public enum Subject
{
BegrijpendLezen,
Rekenen,
Spelling
}

public static class SubjectExtensions
{
public static string ToDisplayName(this Subject subject)
{
return subject switch
{
Subject.BegrijpendLezen => "Begrijpend Lezen",
Subject.Rekenen => "Rekenen",
Subject.Spelling => "Spelling",
_ => throw new ArgumentException($"Unknown subject: {subject}")
};
}

public static Subject FromString(string subjectName)
{
return subjectName switch
{
"Begrijpend Lezen" => Subject.BegrijpendLezen,
"Rekenen" => Subject.Rekenen,
"Spelling" => Subject.Spelling,
_ => throw new ArgumentException($"Unknown subject name: {subjectName}")
};
}
}
10 changes: 10 additions & 0 deletions BackEnd/Domain/Models/SubjectAverage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Domain.Models;

public class SubjectAverage
{
public Subject Subject { get; set; }
public required string SubjectName { get; set; }
public decimal Average { get; set; }
public int TotalExercises { get; set; }
public int StudentCount { get; set; }
}
15 changes: 15 additions & 0 deletions BackEnd/Domain/Models/WorkResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Domain.Models;

public class WorkResult
{
public long SubmittedAnswerId { get; set; }
public DateTime SubmitDateTime { get; set; }
public bool Correct { get; set; }
public decimal Progress { get; set; }
public int UserId { get; set; }
public long ExerciseId { get; set; }
public decimal Difficulty { get; set; }
public Subject Subject { get; set; }
public string Domain { get; set; } = string.Empty;
public string LearningObjective { get; set; } = string.Empty;
}
40 changes: 40 additions & 0 deletions BackEnd/Domain/Queries/GetAllStudentsQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Domain.Models;
using Domain.Repositories;
using Domain.Services;

namespace Domain.Queries;

public class GetAllStudentsQuery
{
private readonly IWorkDataRepository _workDataRepository;
private readonly AverageCalculationService _averageCalculationService;

public GetAllStudentsQuery(
IWorkDataRepository workDataRepository,
AverageCalculationService averageCalculationService)
{
_workDataRepository = workDataRepository;
_averageCalculationService = averageCalculationService;
}

public async Task<IList<StudentListItem>> ExecuteAsync(DateTime cutoffDate)
{
var workResults = await _workDataRepository.GetWorkResultsBeforeDateAsync(cutoffDate);
var students = await _workDataRepository.GetAllStudentsAsync(cutoffDate);

var studentsWithAverages = students.Select(student =>
{
var studentWorkResults = workResults.Where(wr => wr.UserId == student.UserId).ToList();
var subjectAverages = _averageCalculationService.CalculateStudentSubjectAverages(studentWorkResults);

return new StudentListItem
{
UserId = student.UserId,
Name = student.Name,
SubjectAverages = subjectAverages
};
}).ToList();

return studentsWithAverages;
}
}
31 changes: 31 additions & 0 deletions BackEnd/Domain/Queries/GetDashboardAveragesQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Domain.Models;
using Domain.Repositories;
using Domain.Services;

namespace Domain.Queries;

public class GetDashboardAveragesQuery
{
private readonly IWorkDataRepository _workDataRepository;
private readonly AverageCalculationService _averageCalculationService;

public GetDashboardAveragesQuery(
IWorkDataRepository workDataRepository,
AverageCalculationService averageCalculationService)
{
_workDataRepository = workDataRepository;
_averageCalculationService = averageCalculationService;
}

public async Task<DashboardSummary> ExecuteAsync(DateTime cutoffDate)
{
var workResults = await _workDataRepository.GetWorkResultsBeforeDateAsync(cutoffDate);

var subjectAverages = _averageCalculationService.CalculateSubjectAverages(workResults);

return new DashboardSummary
{
SubjectAverages = subjectAverages
};
}
}
55 changes: 55 additions & 0 deletions BackEnd/Domain/Queries/GetStudentDataQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Domain.Models;
using Domain.Repositories;
using Domain.Services;

namespace Domain.Queries;

public class GetStudentDataQuery
{
private readonly IWorkDataRepository _workDataRepository;
private readonly AverageCalculationService _averageCalculationService;

public GetStudentDataQuery(
IWorkDataRepository workDataRepository,
AverageCalculationService averageCalculationService)
{
_workDataRepository = workDataRepository;
_averageCalculationService = averageCalculationService;
}

public async Task<StudentData?> ExecuteAsync(int studentId, DateTime cutoffDate)
{
var allWorkResults = await _workDataRepository.GetWorkResultsBeforeDateAsync(cutoffDate);
var studentWorkResults = allWorkResults.Where(wr => wr.UserId == studentId).ToList();

if (!studentWorkResults.Any())
{
return null;
}

var subjectAverages = _averageCalculationService.CalculateStudentSubjectAverages(studentWorkResults);

var exercises = studentWorkResults
.OrderByDescending(wr => wr.SubmitDateTime)
.Select(wr => new StudentExerciseResult
{
Subject = wr.Subject,
SubjectName = wr.Subject.ToDisplayName(),
ExerciseId = wr.ExerciseId,
ExerciseName = $"Exercise {wr.ExerciseId}",
Correct = wr.Correct,
Difficulty = wr.Difficulty,
Progress = wr.Progress,
SubmitDateTime = wr.SubmitDateTime
})
.ToList();

return new StudentData
{
UserId = studentId,
Name = $"Student {studentId}",
SubjectAverages = subjectAverages,
Exercises = exercises
};
}
}
10 changes: 10 additions & 0 deletions BackEnd/Domain/Repositories/IWorkDataRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Domain.Models;

namespace Domain.Repositories;

public interface IWorkDataRepository
{
Task<IList<WorkResult>> GetWorkResultsBeforeDateAsync(DateTime cutoffDate);
Task<HashSet<int>> GetUniqueStudentIdsAsync(DateTime cutoffDate);
Task<IList<StudentListItem>> GetAllStudentsAsync(DateTime cutoffDate);
}
66 changes: 66 additions & 0 deletions BackEnd/Domain/Services/AverageCalculationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Domain.Models;

namespace Domain.Services;

public class AverageCalculationService
{
public List<SubjectAverage> CalculateSubjectAverages(IList<WorkResult> workResults)
{
var subjectGroups = workResults.GroupBy(wr => wr.Subject);
var subjectAverages = new List<SubjectAverage>();

foreach (var subjectGroup in subjectGroups)
{
var subjectResults = subjectGroup.ToList();
var correctAnswers = subjectResults.Count(wr => wr.Correct);
var totalAnswers = subjectResults.Count;
var averagePercentage = totalAnswers > 0 ? (decimal)correctAnswers / totalAnswers : 0;
var averageOnTenScale = averagePercentage * 10;

var uniqueStudents = subjectResults.Select(wr => wr.UserId).ToHashSet().Count;

subjectAverages.Add(new SubjectAverage
{
Subject = subjectGroup.Key,
SubjectName = subjectGroup.Key.ToDisplayName(),
Average = Math.Round(averageOnTenScale, 1),
TotalExercises = totalAnswers,
StudentCount = uniqueStudents
});
}

return subjectAverages.OrderBy(sa => sa.Subject).ToList();
}

public List<StudentSubjectAverage> CalculateStudentSubjectAverages(IList<WorkResult> studentWorkResults)
{
if (studentWorkResults == null || !studentWorkResults.Any())
{
return new List<StudentSubjectAverage>();
}

var subjectAverages = new List<StudentSubjectAverage>();
var subjectGroups = studentWorkResults.GroupBy(wr => wr.Subject);

foreach (var subjectGroup in subjectGroups)
{
var subjectResults = subjectGroup.ToList();
var correctAnswers = subjectResults.Count(wr => wr.Correct);
var totalAnswers = subjectResults.Count;

if (totalAnswers > 0)
{
var averagePercentage = (decimal)correctAnswers / totalAnswers;
var averageOnTenScale = averagePercentage * 10;

subjectAverages.Add(new StudentSubjectAverage
{
Subject = subjectGroup.Key,
Average = Math.Round(averageOnTenScale, 1)
});
}
}

return subjectAverages.OrderBy(sa => sa.Subject).ToList();
}
}
Loading