Add Blazor WebApp and rework data handling to utilize Entity Framework

This commit is contained in:
2025-09-11 11:49:48 -04:00
parent 5220e61c79
commit 3daa3b81b3
111 changed files with 6039 additions and 946 deletions
@@ -2,15 +2,15 @@
namespace Core.Parsers;
public class AssignmentAssumptionParser : CsvParserBase
public class AssignmentRequirementParser : CsvParserBase
{
public AssignmentAssumptionParser(FileSystemInfo csvFile, bool ignoreBlankLines = true) : base(csvFile, ignoreBlankLines)
public AssignmentRequirementParser(FileSystemInfo csvFile, bool ignoreBlankLines = true) : base(csvFile, ignoreBlankLines)
{
}
public AssignmentAssumption[] Parse(ICollection<CompetitiveEvent> events, ICollection<Student> students)
public AssignmentRequirement[] Parse(ICollection<EventDefinition> events, ICollection<Student> students)
{
var assumptions = new List<AssignmentAssumption>();
var assumptions = new List<AssignmentRequirement>();
CsvReader.Read();
CsvReader.ReadHeader();
@@ -27,7 +27,7 @@ public class AssignmentAssumptionParser : CsvParserBase
var evt = events.FirstOrDefault(e => e.ShortName == eventShortName);
if (evt == null)
throw new Exception($"Could not find event named {eventShortName}");
throw new Exception($"Could not find eventDefinition named {eventShortName}");
for (int i = 0; i <= studentArray.Length; i++)
{
var field = CsvReader.GetField(i + 1);
@@ -35,11 +35,11 @@ public class AssignmentAssumptionParser : CsvParserBase
{
case "x":
case "X":
assumptions.Add(new AssignmentAssumption(evt, studentArray[i], Assumption.Exclude));
assumptions.Add(new AssignmentRequirement(evt, studentArray[i], Requirement.Exclude));
break;
case "i":
case "I":
assumptions.Add(new AssignmentAssumption(evt, studentArray[i], Assumption.Include));
assumptions.Add(new AssignmentRequirement(evt, studentArray[i], Requirement.Include));
break;
default:
break;
+6 -2
View File
@@ -10,9 +10,13 @@ public class CsvParserBase : IDisposable
//private readonly MemoryStream _memoryStream;
protected readonly CsvReader CsvReader;
protected CsvParserBase(FileSystemInfo csvFile, bool ignoreBlankLines)
protected CsvParserBase(FileSystemInfo csvFile, bool ignoreBlankLines) : this(OpenCsv(csvFile), ignoreBlankLines)
{
_reader = OpenCsv(csvFile);
}
protected CsvParserBase(StreamReader reader, bool ignoreBlankLines)
{
_reader = reader;
CsvReader = InitCsvReader(_reader, ignoreBlankLines);
}
+11 -7
View File
@@ -9,21 +9,25 @@ public class EventDefinitionParser : CsvParserBase
{
}
public CompetitiveEvent[] Parse()
public EventDefinitionParser(StreamReader reader, bool ignoreBlankLines = true) : base(reader, ignoreBlankLines)
{
var events = new List<CompetitiveEvent>();
}
public EventDefinition[] Parse()
{
var events = new List<EventDefinition>();
CsvReader.Read();
CsvReader.ReadHeader();
while (CsvReader.Read())
while (CsvReader.Read())
{
var name = CsvReader.GetField("Event");
if (string.IsNullOrEmpty(name))
continue;
var shortName = CsvReader.GetField("Short Name");
Enum.TryParse(CsvReader.GetField("Format"), out EventFormat format);
Enum.TryParse(CsvReader.GetField("EventFormat"), out EventFormat format);
var teamSize = CsvReader.GetField("Team Size");
if (string.IsNullOrEmpty(teamSize))
@@ -47,18 +51,18 @@ public class EventDefinitionParser : CsvParserBase
var levelOfEffort = CsvReader.GetField<int?>("Level of Effort");
//var regionalTeams = CsvReader.GetField<int>("Regional Teams");
var competitiveEvent = new CompetitiveEvent
var competitiveEvent = new EventDefinition
{
Name = name.Trim(),
ShortName = shortName.Trim(),
Format = format,
EventFormat = format,
MaxTeamCountState = stateTeams,
MinTeamSize = min,
MaxTeamSize = max,
SemifinalistActivity = semifinalistActivity,
RegionalEvent = !string.IsNullOrEmpty(regionalCount),
RegionalPresubmit = regionalPresubmit.Trim() == "TRUE",
RegionalNotes = regionalNotes,
Notes = regionalNotes,
Documentation= documentation,
StatePresubmission = statePresubmission.Trim() == "TRUE",
StatePretesting = statePretesting.Trim() == "TRUE",
+12 -12
View File
@@ -7,9 +7,9 @@ namespace Core.Parsers;
public class EventOccurrenceParser
{
private FileSystemInfo _txtFile;
private ICollection<CompetitiveEvent> _events;
private ICollection<EventDefinition> _events;
public EventOccurrenceParser(FileSystemInfo txtFile, ICollection<CompetitiveEvent> events)
public EventOccurrenceParser(FileSystemInfo txtFile, ICollection<EventDefinition> events)
{
_events = events;
_txtFile = txtFile;
@@ -28,10 +28,10 @@ public class EventOccurrenceParser
private readonly Regex _timeLocationRegex = new(@"(?<Time>.*(?>[AaPp]\.?[Mm]\.?))(?<Location>[\s\t].*)?");
public IDictionary<CompetitiveEvent, List<EventOccurrence>> Parse()
public IDictionary<EventDefinition, List<EventOccurrence>> Parse()
{
var occurrences = new Dictionary<CompetitiveEvent, List<EventOccurrence>>();
CompetitiveEvent currentEvent = null;
var occurrences = new Dictionary<EventDefinition, List<EventOccurrence>>();
EventDefinition currentEventDefinition = null;
var lines = File.ReadLines(_txtFile.FullName);
foreach (var line in lines)
@@ -49,25 +49,25 @@ public class EventOccurrenceParser
select e).FirstOrDefault();
if (evt == null)
continue;
currentEvent = evt;
currentEventDefinition = evt;
continue;
}
if (line == "General Schedule")
{
currentEvent = CompetitiveEvent.GeneralSchedule;
currentEventDefinition = EventDefinition.GeneralSchedule;
continue;
}
if (line == "Voting Delegates")
{
currentEvent = CompetitiveEvent.VotingDelegates;
currentEventDefinition = EventDefinition.VotingDelegates;
continue;
}
continue;
}
if (currentEvent == null)
if (currentEventDefinition == null)
continue;
var occurrenceName = match.Groups["Name"].Captures[0].Value;
@@ -103,9 +103,9 @@ public class EventOccurrenceParser
Location = location
};
if (!occurrences.ContainsKey(currentEvent))
occurrences.Add(currentEvent, []);
occurrences[currentEvent].Add(eventOccurrence);
if (!occurrences.ContainsKey(currentEventDefinition))
occurrences.Add(currentEventDefinition, []);
occurrences[currentEventDefinition].Add(eventOccurrence);
}
return occurrences;
+77
View File
@@ -0,0 +1,77 @@
using Core.Entities;
using FuzzySharp;
namespace Core.Parsers;
public class StudentEventRankingParser : CsvParserBase
{
public StudentEventRankingParser(FileSystemInfo csvFile, bool ignoreBlankLines = true) : base(csvFile, ignoreBlankLines)
{
}
public StudentEventRanking[] Parse(ICollection<Student> students, ICollection<EventDefinition> events)
{
var rankings = new List<StudentEventRanking>();
CsvReader.Read();
CsvReader.ReadHeader();
while (CsvReader.Read())
{
var name = CsvReader.GetField("Student Name");
if (string.IsNullOrEmpty(name))
continue;
var student = students.FirstOrDefault(s => Fuzz.Ratio(s.FirstNameLastName, name) > 90);
if (student == null)
continue;
var competitiveEvents = new List<EventDefinition>(6);
for (var i = 1; i <= 6; i++)
{
var eventName = CsvReader.GetField(i.ToString());
if (string.IsNullOrEmpty(eventName) || eventName == "") continue;
eventName = eventName.Trim();
if (eventName == "I&I")
eventName = "Inventions & Innovations";
if (eventName == "Med Tech")
eventName = "Medical Technology";
if (eventName.StartsWith("Challenging Tech"))
eventName = "Challenging Technology Issues";
var matches =
(from e in events
let rat = Fuzz.Ratio(e.Name, eventName)
where rat > 90
orderby rat descending
select e).ToList();
if (!matches.Any())
{
matches =
(from e in events
where e.Name.StartsWith(eventName)
select e).ToList();
}
var competitiveEvent = matches.FirstOrDefault();
if (competitiveEvent == null)
{
//todo: throw new ArgumentException($"Event named '{eventName}' not found");
continue;
}
rankings.Add(new StudentEventRanking{
Student = student, EventDefinition = competitiveEvent,
Rank = i});
}
}
return rankings.ToArray();
}
}
+21 -58
View File
@@ -1,6 +1,4 @@
using Core.Entities;
using FuzzySharp;
namespace Core.Parsers;
public class StudentParser : CsvParserBase
@@ -9,7 +7,11 @@ public class StudentParser : CsvParserBase
{
}
public Student[] Parse(ICollection<CompetitiveEvent> events)
public StudentParser(StreamReader reader, bool ignoreBlankLines = true) : base(reader, ignoreBlankLines)
{
}
public Student[] Parse()
{
var s = new List<Student>();
@@ -22,65 +24,26 @@ public class StudentParser : CsvParserBase
if (string.IsNullOrEmpty(name))
continue;
var stateID = CsvReader.GetField("State ID").Trim();
var regionalID = CsvReader.GetField("Regional ID").Trim();
var nationalID = CsvReader.GetField("National ID").Trim();
var gr = CsvReader.GetField("Grade");
var (firstName, lastName) = Student.ParseNameParts(name);
var stateId = CsvReader.GetField("State ID")?.Trim();
var regionalId = CsvReader.GetField("Regional ID")?.Trim();
var nationalId = CsvReader.GetField("National ID")?.Trim();
var grade = CsvReader.GetField("Grade");
var tsaYearsStr = CsvReader.GetField("TSA year");
var tsaYear = int.Parse(tsaYearsStr?[..1] ?? "1");
var officer = CsvReader.GetField("Officer");
var competitiveEvents = new List<CompetitiveEvent>(6);
for (var i = 1; i <= 6; i++)
var student = new Student
{
var eventName = CsvReader.GetField(i.ToString());
if (string.IsNullOrEmpty(eventName) || eventName == "") continue;
eventName = eventName.Trim();
if (eventName == "I&I")
eventName = "Inventions & Innovations";
if (eventName == "Med Tech")
eventName = "Medical Technology";
if (eventName.StartsWith("Challenging Tech"))
eventName = "Challenging Technology Issues";
var matches =
(from e in events
let rat = Fuzz.Ratio(e.Name, eventName)
where rat > 90
orderby rat descending
select e).ToList();
if (!matches.Any())
{
matches =
(from e in events
where e.Name.StartsWith(eventName)
select e).ToList();
}
var competitiveEvent = matches.FirstOrDefault();
if (competitiveEvent == null)
{
//todo: throw new ArgumentException($"Event named '{eventName}' not found");
continue;
}
competitiveEvents.Add(competitiveEvent);
}
if (!competitiveEvents.Any())
continue;
var student = new Student(
name.Trim(),
Convert.ToInt32(gr),
tsaYear,
officer?.Trim(),
competitiveEvents, stateID, regionalID, nationalID);
FirstName = firstName,
LastName = lastName,
Grade = Convert.ToInt32(grade),
TsaYear = tsaYear,
StateId = stateId,
RegionalId = regionalId,
NationalId = nationalId
};
s.Add(student);
}
+7 -8
View File
@@ -56,7 +56,7 @@ namespace Core.Parsers
{
}
public Team[] Parse(ICollection<CompetitiveEvent> events, ICollection<Student> students)
public Team[] Parse(ICollection<EventDefinition> events, ICollection<Student> students)
{
var teams = new List<Team>();
@@ -139,22 +139,21 @@ namespace Core.Parsers
var teamNumber = string.Empty;
if (teamName.EndsWith("Team 2"))
teamNumber = "12227-2";
else if (@event.Format == EventFormat.Team)
else if (@event.EventFormat == EventFormat.Team)
teamNumber = "2227";
if (teamStudents.Count > 0)
{
if (@event.Format is EventFormat.Team)
if (@event.EventFormat is EventFormat.Team)
{
teams.Add(new Team(teamName, @event, teamStudents, captain, teamNumber,
regionalTimeSlot: regionalTimeSlot));
teams.Add(new Team { Event = @event, Students = teamStudents, Captain = captain, Name = teamName, TeamId = teamNumber});
}
else if (@event.Format is EventFormat.Individual)
else if (@event.EventFormat is EventFormat.Individual)
{
foreach (var student in teamStudents)
{
teams.Add(new Team($"{teamName} - {student.FirstName}", @event,
new List<Student> { student }, student, teamNumber, regionalTimeSlot));
teams.Add(new Team{Name = $"{teamName} - {student.FirstName}", Event = @event,
Students = new List<Student> { student }, Captain = student, TeamId = teamNumber});
}
}
}