diff --git a/web/Areas/Computing/Controllers/PersonController.cs b/web/Areas/Computing/Controllers/PersonController.cs index 805045f..c5ed57b 100644 --- a/web/Areas/Computing/Controllers/PersonController.cs +++ b/web/Areas/Computing/Controllers/PersonController.cs @@ -22,7 +22,7 @@ public PersonController(VIPERContext context, IHttpClientFactory factory) } [HttpGet] - public async Task>> GetPeople(bool? active = null) + public async Task>> GetPeople(bool? active = null, string? name = null) { var people = context.People .AsQueryable(); @@ -30,6 +30,10 @@ public async Task>> GetPeople(bool? active = nul { people = people.Where(p => p.Current == 1 || p.Future == 1); } + if(name != null) + { + people = people.Where(p => p.FirstName.Contains(name) || p.LastName.Contains(name)); + } return await people .OrderBy(p => p.LastName) .ThenBy(p => p.FirstName) diff --git a/web/Areas/Students/Controller/DvmController.cs b/web/Areas/Students/Controller/DvmController.cs index 0b84cdb..04c42f0 100644 --- a/web/Areas/Students/Controller/DvmController.cs +++ b/web/Areas/Students/Controller/DvmController.cs @@ -52,22 +52,17 @@ public DvmStudentsController(VIPERContext context, RAPSContext rapsContext) } /// - /// Get all student class years records for a given class year. Returns students with the class year as their active year only. + /// Get a single student /// - /// + /// /// - [HttpGet("byClassYear/{classYear}")] - [Permission(Allow = "SVMSecure.SIS.AllStudents")] - public async Task>> GetDvmStudentGradYears(int classYear) + [HttpGet("{personId}")] + [Permission(Allow ="SVMSecure.Students")] + public async Task> GetDvmStudent(int personId) { - //get students with all grad years - var students = context.StudentClassYears - .Where(s => s.ClassYear == classYear && s.Active) - .OrderBy(s => s.Student == null ? "" : s.Student.LastName) - .ThenBy(s => s.Student == null ? "" : s.Student.FirstName); - - return await students.ToListAsync(); - } + var student = await studentList.GetStudent(personId); + return student == null ? NotFound() : student; + } /// /// Get students by term and class level. Uses AAUD student info table, which is driven by registration data and exceptions. @@ -82,6 +77,15 @@ public async Task>> GetDvmStudentGrad return await studentList.GetStudentsByTermCodeAndClassLevel(termCode, classLevel); } + [HttpGet("classYearReport")] + [Permission(Allow = "SVMSecure.SIS.AllStudents")] + public async Task>> ClassYearReport(int? classYear) + { + var problems = await studentList.GetStudentClassYearProblems(classYear); + return problems; + } + + /// /// Import the listed people into a class year. Must be their first class year. /// @@ -262,10 +266,10 @@ public async Task>> GetClassYears(bool activeOnly = true, { var termCodeService = new TermCodeService(context); List activeClassYears = (await termCodeService.GetActiveClassYears((await termCodeService.GetActiveTerm()).TermCode)); - if(!activeOnly) + if (!activeOnly) { var minCY = activeClassYears[0]; - for(var i = minCY - 1; i >= (minClassYear ?? minCY - 10); i--) + for (var i = minCY - 1; i >= (minClassYear ?? minCY - 10); i--) { activeClassYears = activeClassYears.Prepend(i).ToList(); } diff --git a/web/Areas/Students/Controller/StudentsController.cs b/web/Areas/Students/Controller/StudentsController.cs index 8a1a76f..e11f1db 100644 --- a/web/Areas/Students/Controller/StudentsController.cs +++ b/web/Areas/Students/Controller/StudentsController.cs @@ -2,6 +2,10 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.EntityFrameworkCore; +using Polly; +using Viper.Areas.CMS.Data; +using Viper.Areas.Curriculum.Services; +using Viper.Areas.Students.Services; using Viper.Classes; using Viper.Classes.SQLContext; using Web.Authorization; @@ -33,18 +37,17 @@ public override async Task OnActionExecutionAsync(ActionExecutingContext context ActionExecutionDelegate next) { await base.OnActionExecutionAsync(context, next); - await next(); ViewData["ViperLeftNav"] = Nav(); } public NavMenu Nav() { - var nav = new List + var menu = new LeftNavMenu().GetLeftNavMenus(friendlyName: "viper-students")?.FirstOrDefault(); + if (menu != null) { - new() { MenuItemText = "Home", MenuItemURL = "Home" } - }; - - return new NavMenu("Student Resources", nav); + ConvertNavLinksForDevelopment(menu); + } + return menu ?? new NavMenu("", new List()); } [Route("/[area]")] @@ -54,11 +57,18 @@ public IActionResult Index() } [Route("/[area]/[action]")] - public IActionResult StudentClassYear(string? import = null, int? classYear= null) + public IActionResult StudentClassYear(string? import = null, int? classYear = null) { - return import != null + return import != null ? View("~/Areas/Students/Views/StudentClassYearImport.cshtml") : View("~/Areas/Students/Views/StudentClassYear.cshtml"); } + + [Route("/[area]/[action]")] + public IActionResult StudentClassYearreport() + { + return View("~/Areas/Students/Views/StudentClassYearReport.cshtml"); + } + } } diff --git a/web/Areas/Students/Models/Student.cs b/web/Areas/Students/Models/Student.cs index d8b31d5..3b5bd6a 100644 --- a/web/Areas/Students/Models/Student.cs +++ b/web/Areas/Students/Models/Student.cs @@ -11,7 +11,8 @@ public class Student public string FirstName { get; set; } = null!; public string? MiddleName { get; set; } public string FullName { get; set; } = null!; - public string? ClassLevel { get; set; } = null!; + public string? ClassLevel { get; set; } + public int? TermCode { get; set; } public int? ClassYear { get; set; } public string Email => MailId + "@ucdavis.edu"; public bool CurrentClassYear { get; set; } @@ -24,6 +25,22 @@ public Student() } + public Student(Student s) + { + PersonId = s.PersonId; + MailId = s.MailId; + LastName = s.LastName; + FirstName = s.FirstName; + MiddleName = s.MiddleName; + FullName = s.FullName; + ClassLevel = s.ClassLevel; + TermCode = s.TermCode; + ClassYear = s.ClassYear; + CurrentClassYear = s.CurrentClassYear; + Active = s.Active; + ClassYears = s.ClassYears; + } + public Student(Person p) { PersonId = p.PersonId; @@ -33,6 +50,7 @@ public Student(Person p) MiddleName = p.MiddleName; FullName = p.FullName; ClassLevel = p.StudentInfo?.ClassLevel; + TermCode = p.StudentInfo?.TermCode; Active = p.CurrentStudent || p.FutureStudent; CurrentClassYear = false; } diff --git a/web/Areas/Students/Models/StudentClassYearProblem.cs b/web/Areas/Students/Models/StudentClassYearProblem.cs new file mode 100644 index 0000000..df77ac9 --- /dev/null +++ b/web/Areas/Students/Models/StudentClassYearProblem.cs @@ -0,0 +1,10 @@ +namespace Viper.Areas.Students.Models +{ + public class StudentClassYearProblem : Student + { + public int? ExpectedClassYear { get; set; } + public string Problems { get; set; } = string.Empty; + + public StudentClassYearProblem(Student s) : base(s) { } + } +} diff --git a/web/Areas/Students/Services/GradYearClassLevel.cs b/web/Areas/Students/Services/GradYearClassLevel.cs index 7c52b76..9d3852e 100644 --- a/web/Areas/Students/Services/GradYearClassLevel.cs +++ b/web/Areas/Students/Services/GradYearClassLevel.cs @@ -1,4 +1,5 @@ -using Microsoft.Identity.Client; +using Microsoft.AspNetCore.Connections.Features; +using Microsoft.Identity.Client; namespace Viper.Areas.Students.Services { @@ -29,14 +30,68 @@ public class GradYearClassLevel //202309: V1 2027 V4 2024 //202402: V1 2027 V4 2024 //202404: V4 2025 - if(term == 2 || term == 4 || term == 9) + if (term == 2 || term == 4 || term == 9) { return year + (5 - classYear) - (term == 2 ? 1 : 0); } - } + } return null; } + /// + /// Get the "best" termcode and class level for a grad year. + /// For V1-V3, use the current term if it's fall or spring. If it's summer, use the upcoming fall term. + /// For V4, use the current term. + /// If the grad year is in the past, use the spring term they graduated. + /// + /// + /// + /// + static public Tuple GetTermCodeAndClassLevelForGradYear(int gradYear, int currentTerm) + { + int termYear = currentTerm / 100; + int termPart = currentTerm % 100; + if (gradYear <= termYear) + { + return Tuple.Create((termYear * 100) + 2, "V4"); + } + + var termAndClassLevel = Tuple.Create(currentTerm, ""); + switch (termPart) + { + case 2: + termAndClassLevel = Tuple.Create(currentTerm, "V" + (4 - (gradYear - termYear)).ToString()); + break; + case 9: + termAndClassLevel = Tuple.Create(currentTerm, "V" + (5 - (gradYear - termYear)).ToString()); + break; + case 4: + if (gradYear - termYear == 1) + { + termAndClassLevel = Tuple.Create(currentTerm, "V4"); + } + else + { + termAndClassLevel = Tuple.Create((termYear * 100) + 9, "V" + (5 - (gradYear - termYear)).ToString()); + } + break; + } + + if (ValidClassYears.Contains(termAndClassLevel.Item2)) + { + return termAndClassLevel; + } + + //grad year is a future class level, they will enter fall of grad year - 4 + return Tuple.Create(((gradYear - 4) * 100) + 9, "V1"); + } + + /// + /// Get the DVM class level (V1-V4) for the given grad year and the current term code + /// + /// + /// + /// static public string GetDvmClassLevel(int gradYear, int termCode) { var classLevel = ""; @@ -60,7 +115,7 @@ static public string GetDvmClassLevel(int gradYear, int termCode) //Summer and Fall - if they graduate next year, V4, if they graduate two years from now, V3, etc.} else { - switch(gradYear - currentYear) + switch (gradYear - currentYear) { case 1: classLevel = "V4"; break; @@ -70,7 +125,7 @@ static public string GetDvmClassLevel(int gradYear, int termCode) default: break; } } - + return classLevel; } diff --git a/web/Areas/Students/Services/StudentList.cs b/web/Areas/Students/Services/StudentList.cs index 7c7aa38..29af66c 100644 --- a/web/Areas/Students/Services/StudentList.cs +++ b/web/Areas/Students/Services/StudentList.cs @@ -3,41 +3,55 @@ using Viper.Areas.Students.Models; using Viper.Classes.SQLContext; using Viper.Models.Students; +using static System.Runtime.CompilerServices.RuntimeHelpers; namespace Viper.Areas.Students.Services { - public class StudentList + public class StudentList { private readonly VIPERContext _context; - public StudentList(VIPERContext context) { + public StudentList(VIPERContext context) + { _context = context; } - public async Task> GetStudents(string? classLevel = null, int? classYear = null, bool currentYearsOnly = true, - bool includeRoss = true, bool activeYearOnly = true) + /// + /// Get a list of students using the given parameters. Calculate their current class year and all class years they've been a part of. + /// + /// + /// + /// + /// + /// + /// + public async Task> GetStudents(string? classLevel = null, int? classYear = null, int? personId = null, + bool currentYearsOnly = true, bool includeRoss = true, bool activeYearOnly = true) { var termCodeService = new TermCodeService(_context); int termCode = (await termCodeService.GetTerms(current: true)).First().TermCode; + List currentClassYears = await termCodeService.GetActiveClassYears(termCode); + + //if class level is specified, translate to a class year using the current termcode, e.g. V4 in Summer 2024 is class of 2025 if (!string.IsNullOrEmpty(classLevel)) { var gradYearFromClassLevel = GradYearClassLevel.GetGradYear(classLevel, termCode); - if(classYear != null && classYear != gradYearFromClassLevel) + if (classYear != null && classYear != gradYearFromClassLevel) { return new List(); } - if(classYear == null) + if (classYear == null) { - classYear = gradYearFromClassLevel; + classYear = gradYearFromClassLevel; } } - List activeClassYear = await termCodeService.GetActiveClassYears(termCode); var q = _context.StudentClassYears .Include(q => q.ClassYearLeftReason) .Include(q => q.Student) .ThenInclude(q => q!.StudentInfo) .Where(q => includeRoss || !q.Ross); + //include only the active class year for this student if (activeYearOnly) { if (classYear != null) @@ -46,15 +60,25 @@ public async Task> GetStudents(string? classLevel = null, int? cla } q = q.Where(q => q.Active); } - else if (classYear != null) - { + //include all class years, as long as at least one of them is the given year + else if (classYear != null) + { //get all students that have a class year entry in this year - var studentPersonIds = _context.StudentClassYears.Where(g => g.ClassYear == classYear).Select(g => g.PersonId).ToList(); - q = q.Where(q => q.Student != null && studentPersonIds.Contains(q.Student.PersonId)); - } - if(currentYearsOnly) + q = q.Where(q => q.Student != null && _context.StudentClassYears + .Where(anyClassYear => anyClassYear.ClassYear == classYear && anyClassYear.PersonId == q.Student.PersonId) + .Any() + ); + } + + if (personId != null) + { + q = q.Where(q => q.PersonId == personId); + } + + //include only the current class years, i.e. V1-V4 students now + if (currentYearsOnly) { - q = q.Where(q => activeClassYear.Contains(q.ClassYear)); + q = q.Where(q => currentClassYears.Contains(q.ClassYear)); } q = q @@ -63,15 +87,26 @@ public async Task> GetStudents(string? classLevel = null, int? cla .ThenBy(q => q.Student == null ? 0 : q.Student.PersonId) .ThenBy(q => q.Active ? 1 : 0) .ThenBy(q => q.ClassYear); - + var studentList = CreateStudentListFromStudentGradYears(await q.ToListAsync(), activeYearOnly: activeYearOnly); - foreach(var s in studentList) + foreach (var s in studentList) { - s.CurrentClassYear = s.ClassYear != null && activeClassYear.Contains((int)s.ClassYear); + s.CurrentClassYear = s.ClassYear != null && currentClassYears.Contains((int)s.ClassYear); } return studentList; } + public async Task GetStudent(int personId) + { + return (await GetStudents(personId: personId)).FirstOrDefault(); + } + + /// + /// Get students from AAUD based on term code and class level + /// + /// + /// + /// public async Task> GetStudentsByTermCodeAndClassLevel(int termCode, string classLevel) { //Get students based on AAUD Student info for the given term @@ -89,25 +124,116 @@ public async Task> GetStudentsByTermCodeAndClassLevel(int termCode .Include(s => s.ClassYearLeftReason) .Where(s => studentIds.Contains(s.PersonId)) .OrderBy(g => g.Active ? 0 : 1) - .ThenByDescending(g => g.ClassYear); + .ThenByDescending(g => g.ClassYear) + .AsNoTracking() + .ToList(); foreach (var student in studentList) { var studentGradYears = gradYears - .Where(g => g.PersonId == student.PersonId) - .ToList(); - student.ClassYears = studentGradYears; + .Where(g => g.PersonId == student.PersonId) + .ToList(); + student.ClassYears = new List(); + foreach (var cy in studentGradYears) + { + student.ClassYears.Add(new StudentClassYear(cy)); + } student.ClassYear = studentGradYears?.FirstOrDefault()?.ClassYear; } return studentList; } - private List CreateStudentListFromStudentGradYears(List studentGradYears, bool activeYearOnly = true) + /// + /// Return a list of students, either for a single class year or for all active class years, + /// that appear to be in a different class year based on their class level for the current term + /// + /// + public async Task> GetStudentClassYearProblems(int? classYear = null) + { + var termCodeService = new TermCodeService(_context); + int termCode = (await termCodeService.GetTerms(current: true)).First().TermCode; + + if (classYear != null) + { + return await GetStudentClassYearProblemsForOneYear((int)classYear, termCode); + } + + List activeClassYears = await termCodeService.GetActiveClassYears(termCode); + List students = new(); + foreach (var cy in activeClassYears) + { + var classYearProblems = await GetStudentClassYearProblemsForOneYear(cy, termCode); + students = students + .Concat(classYearProblems.Where(newProblem => !students.Any(s => s.PersonId == newProblem.PersonId))) + .OrderBy(s => s.LastName) + .ThenBy(s => s.FirstName) + .ToList(); + } + + return students; + } + + /// + /// Return a list of students for a single class year that appear to be in a different class year based on + /// their class level for the current term, or should be in this class year but aren't + /// + /// + private async Task> GetStudentClassYearProblemsForOneYear(int classYear, int currentTerm) + { + List studentProblems = new(); + + //Get all students in this class year currently + var studentsInClassYear = await GetStudents(classYear: classYear); + + //Get the best class level and term code to use, based on the class year and current term + var (termCode, classLevel) = GradYearClassLevel.GetTermCodeAndClassLevelForGradYear(classYear, currentTerm); + + //Get all students that, in the current term, should be considered a part of this class year + var expectedStudents = await GetStudentsByTermCodeAndClassLevel(termCode, classLevel); + + //For each student in this class year currently, check that they are in the expected students + foreach (var s in studentsInClassYear) + { + if (!expectedStudents.Any(e => e.PersonId == s.PersonId)) + { + var expected = (s.ClassLevel != null && s.TermCode != null) ? GradYearClassLevel.GetGradYear(s.ClassLevel, (int)s.TermCode) : null; + studentProblems.Add(new StudentClassYearProblem(s) + { + ExpectedClassYear = expected, + Problems = string.Format("Student is in class year {0}, but is not registgered as {1} in {2}.", s.ClassYear, classLevel, termCode) + }); + } + } + + //For each student that should be considered part of this class year based on class level and term code, check that they are in the class year. + foreach (var e in expectedStudents) + { + if (!studentsInClassYear.Any(s => s.PersonId == e.PersonId) && !studentProblems.Any(p => p.PersonId == e.PersonId)) + { + var expected = (e.ClassLevel != null && e.TermCode != null) ? GradYearClassLevel.GetGradYear(e.ClassLevel, (int)e.TermCode) : null; + studentProblems.Add(new StudentClassYearProblem(e) + { + ExpectedClassYear = expected, + Problems = string.Format("Student is in {0}, but is not registered as {1} in {2}.", expected, classLevel, termCode) + }); + } + } + + return studentProblems; + } + + /// + /// Given a list of grad years for a student, create a student object with all class years they've been a part of + /// + /// + /// + /// + private static List CreateStudentListFromStudentGradYears(List studentGradYears, bool activeYearOnly = true) { var students = new List(); - foreach (var student in studentGradYears.GroupBy(s => s.PersonId)) + foreach (var student in studentGradYears.GroupBy(s => s.PersonId)) { var std = student.First(); - if (std.Student != null) + if (std.Student != null) { var newStd = new Student() { @@ -118,22 +244,33 @@ private List CreateStudentListFromStudentGradYears(List classYears = new List(); + if (!activeYearOnly) { - newStd.ClassYears = student.ToList(); - } + classYears = student.ToList(); + } else { - newStd.ClassYears = student.Where(s => s.Active).ToList(); + classYears = student.Where(s => s.Active).ToList(); + } + + newStd.ClassYears = new List(); + foreach (var cy in classYears) + { + newStd.ClassYears.Add(new StudentClassYear(cy)); } + students.Add(newStd); } } return students; } + } } diff --git a/web/Areas/Students/Views/StudentClassYear.cshtml b/web/Areas/Students/Views/StudentClassYear.cshtml index 0841dbc..dbfe0e0 100644 --- a/web/Areas/Students/Views/StudentClassYear.cshtml +++ b/web/Areas/Students/Views/StudentClassYear.cshtml @@ -1,170 +1,244 @@ - +
+
+

Student Class Years

+
+
+ - - - -
Updating record for {{selectedStudentName}} Class of {{studentClassYear.classYear}}
- If you change the class year one the current class year, a new record will be created and the current class year one will be marked - as inactive with the reasons and term below. -
- - -
- - @* :true-value="1" :false-value="0" *@ -
If changing class year, please fill out below.
- - - - -
- - - - -
-
+ + + +
Updating record for {{selectedStudentName}} Class of {{studentClassYear.classYear}}
+ If you change the class year one the current class year, a new record will be created and the current class year one will be marked + as inactive with the reasons and term below. +
+ + +
+ + @* :true-value="1" :false-value="0" *@ +
If changing class year, please fill out below.
+ + + + +
+ + + + +
+
-
- - - - -
- -
- - - {{classYear.label}} - - - - - - - - - {{student.lastName}}, {{student.firstName}} - - - - Ross - {{studentClassYear.leftReasonText}} - - - - -
-
- No students found. Please import this class year. -
+
+
+ + + +
+ +
+
+ +
+
+ + + + + + + + @section Scripts { - + this.studentClassYear = { ...cy } + this.showForm = true + }, + submitStudentClassYear: async function () { + var u = "@Url.Content("~/api/students/dvm/")" + this.studentClassYear.classYear + "/" + this.studentClassYear.personId + await viperFetch(this, + u, + { + method: "PUT", + body: JSON.stringify(this.studentClassYear), + headers: { "Content-Type": "application/json" } + } + ) + this.getStudents() + this.clear() + }, + deleteStudentClassYear: async function () { + var u = "@Url.Content("~/api/students/dvm/studentClassYears/")" + this.studentClassYear.studentClassYearId + await viperFetch(this, + u, + { + method: "DELETE", + headers: { "Content-Type": "application/json" } + } + ) + this.getStudents() + this.clear() + }, + toImport: function () { + location.href = "?import=1&classYear=" + this.classYear.value + } + }, + mounted: async function () { + //get class year from url + var cy = this.urlParams.get("classYear") ?? "" + if (cy) { + this.classYear = { label: "Class of " + cy, value: cy } + } + //get all class years, reasons, terms for select boxes + this.classYearOptions.push({ label: "", value: "" }) + for (var i = new Date().getFullYear() + 6; i >= 2016; i--) { + this.classYearOptions.push({ label: "Class of " + i, value: i }) + } + viperFetch(this, "@Url.Content("~/curriculum/terms")") + .then(data => { + this.terms = data + .map(t => ({ label: t.description, value: t.termCode })) + }) + viperFetch(this, "@Url.Content("~/api/students/dvm/leftReasons")") + .then(data => { + this.reasons = data + .map(r => ({ label: r.reason, value: r.classYearLeftReasonId })) + }) + //get students + this.getStudents() + }, + watch: { + problemsOnly: function () { + this.students = this.allStudents.filter(s => !this.problemsOnly || s?.problems?.length) + } + } + }) + } \ No newline at end of file diff --git a/web/Areas/Students/Views/StudentClassYearImport.cshtml b/web/Areas/Students/Views/StudentClassYearImport.cshtml index 26980f4..a255865 100644 --- a/web/Areas/Students/Views/StudentClassYearImport.cshtml +++ b/web/Areas/Students/Views/StudentClassYearImport.cshtml @@ -1,4 +1,8 @@ -

Student Class Year Import

+
+
+

Student Class Year Import

+
+
diff --git a/web/Models/Person.cs b/web/Models/Person.cs index 2c72e2a..9ddf810 100644 --- a/web/Models/Person.cs +++ b/web/Models/Person.cs @@ -14,6 +14,7 @@ public class PersonSimple public string FullName => $"{FirstName} {LastName}"; public string FullNameLastFirst => $"{LastName}, {FirstName}"; + public string Email => $"{MailId}@ucdavis.edu"; public PersonSimple() { } public PersonSimple(Person p) diff --git a/web/Models/Students/StudentClassYear.cs b/web/Models/Students/StudentClassYear.cs index 42a521f..d16f4cd 100644 --- a/web/Models/Students/StudentClassYear.cs +++ b/web/Models/Students/StudentClassYear.cs @@ -5,6 +5,7 @@ namespace Viper.Models.Students { public class StudentClassYear { + public int StudentClassYearId { get; set; } public int PersonId { get; set; } public int ClassYear { get; set; } @@ -32,5 +33,27 @@ public string? LeftReasonText return ClassYearLeftReason?.Reason; } } + + public StudentClassYear() + { + + } + public StudentClassYear(StudentClassYear cy) + { + StudentClassYearId = cy.StudentClassYearId; + PersonId = cy.PersonId; + ClassYear = cy.ClassYear; + Active = cy.Active; + Graduated = cy.Graduated; + Ross = cy.Ross; + LeftTerm = cy.LeftTerm; + LeftReason = cy.LeftReason; + Added = cy.Added; + Updated = cy.Updated; + AddedBy = cy.AddedBy; + UpdatedBy = cy.UpdatedBy; + Comment = cy.Comment; + ClassYearLeftReason = cy.ClassYearLeftReason; + } } } diff --git a/web/Program.cs b/web/Program.cs index 7f1d7bf..d10f862 100644 --- a/web/Program.cs +++ b/web/Program.cs @@ -254,7 +254,7 @@ var baseUrl = app.Environment.IsDevelopment() ? "" : "2/"; RewriteOptions rewriteOptions = new RewriteOptions() .AddRewrite(@"(?i)^CTS", "/vue/src/cts/index.html", true) - .AddRewrite(@"(?i)^Computing", "/vue/src/computing/index.html", true); ; + .AddRewrite(@"(?i)^Computing", "/vue/src/computing/index.html", true); app.UseRewriter(rewriteOptions); //for the vue src files, use directories in the url but serve index.html