} // End of AddCohort /// <summary> /// Business logic for modifying Cohort records /// </summary> /// <param name="cohort"></param> /// <returns></returns> internal object ModifyCohortBLL(CohortDTO cohort) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Check if the id matches a CohortID already in the database. if (!CohortExists(cohort.CohortID)) { exceptionList.AddExMessage($"Cohort does not exist with the ID {cohort.CohortID}"); } else { // Check if the supplied changes meet requirements as for addition if (cohort.Name == null || cohort.Name.Trim() == string.Empty) { exceptionList.AddExMessage("Name parameter cannot be empty."); } else { // Check if a cohort with the same name exists in the database (trim + case insensitive) // If it does, it has to have a different CohortID from the one supplied (i.e. ignore if they have the same ID) bool dbContainsName = _context.Cohorts.Any(x => (x.Name.ToLower() == cohort.Name.Trim().ToLower()) && (x.CohortID != cohort.CohortID)); if (dbContainsName) { exceptionList.AddExMessage("A cohort with the same name already exists in the database."); } // Check that the startDate is less than endDate bool datesConsistent = cohort.StartDate < cohort.EndDate; if (!datesConsistent) { exceptionList.AddExMessage("Start date must be before the end date, check for consistency."); } } } if (!exceptionList.HasExceptions) { // New database name will be trimmed and in Proper Case. string dbName = String.Join(" ", cohort.Name.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); // Create a new Cohort object Cohort newDbObject = new Cohort { CohortID = cohort.CohortID, Name = dbName, StartDate = cohort.StartDate, EndDate = cohort.EndDate }; // Return the Cohort object (conversion from CohortDTO for internal ops) return(newDbObject); } else { return(exceptionList); } } // End of ModifyCohort
} // End of GetNoticeBLL /// <summary> /// Business logic for processing Notice record addition /// </summary> /// <param name="notice"></param> /// <returns></returns> internal object AddNoticeBLL(NoticeDTO notice, ClaimsPrincipal userClaims) { // Get the StaffID of the currently logged in Staff member int loggedInStaffID = _context.Users.Where(x => x.Email == userClaims.FindFirst("Email").Value).Include(user => user.StaffData).Select(x => x.StaffData.StaffID).FirstOrDefault(); // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "cohortID must be valid", notice.CohortID != 0 && !_context.Cohorts.Any(x => x.CohortID == notice.CohortID) }, { "staffID must be valid", notice.StaffID != 0 && !_context.Staff.Any(x => x.StaffID == notice.StaffID) }, { "Notice text should not be null or empty", string.IsNullOrEmpty(notice.HTML.Trim()) || string.IsNullOrEmpty(notice.Markdown.Trim()) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { notice.StaffID = loggedInStaffID; return(notice); } else { return(exceptionList); } } // End of AddNoticeBLL
/// <summary> /// Business logic for detailed Student records /// </summary> /// <param name="cohortID"></param> /// <returns></returns> internal object StudentDetailBLL(int cohortID) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "Specified CohortID does not exist", !(_context.Cohorts.Any(x => x.CohortID == cohortID) || cohortID == 0) }, { "Specified cohort is inactive.", cohortID != 0 && !_context.Cohorts.Any(x => x.CohortID == cohortID && DateTime.Now >= x.StartDate && DateTime.Now <= x.EndDate) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { return(cohortID); } else { return(exceptionList); } } // End of StudentDetailBLL
/// <summary> /// Business logic for processing TaskType record addition /// </summary> /// <param name="description"></param> /// <returns></returns> internal object AddTaskTypeBLL(string description) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "description parameter cannot be empty", description == null || description.Trim() == string.Empty }, { "description must be unique", !string.IsNullOrEmpty(description) && _context.TaskTypes.Any(x => x.Description.ToLower() == description.Trim().ToLower()) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // Capitalise the first letter of the first word of the description string dbDescription = $"{description.Trim().Substring(0, 1).ToUpper()}{description.Trim().Substring(1)?.ToLower()}"; TaskTypeDTO newDbObject = new TaskTypeDTO { Description = dbDescription }; return(newDbObject); } else { return(exceptionList); } } // End of AddTaskTypeBLL
} // End of AddTaskBLL /// <summary> /// Business logic for processing modifications to the Task record /// </summary> /// <param name="task"></param> /// <returns></returns> internal object ModifyTaskBLL(TaskDTO task) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "title cannot be empty.", task.Title == null || task.Title.Trim() == string.Empty }, { "Specified UnitID does not exist", !_context.Units.Any(x => x.UnitID == task.UnitID) }, { "Specified CohortID does not exist", !_context.Cohorts.Any(x => x.CohortID == task.CohortID) }, { "Specified TypeID does not exist", !_context.TaskTypes.Any(x => x.TypeID == task.TypeID) }, { "Document URL must start with http:// or https://", !string.IsNullOrEmpty(task.DocURL) && !(task.DocURL.ToLower().StartsWith("http://") | task.DocURL.ToLower().StartsWith("https://")) }, { "Document URL must be valid", !string.IsNullOrEmpty(task.DocURL) && !Uri.IsWellFormedUriString(task.DocURL, UriKind.Absolute) }, { "Specified cohort is inactive.", !_context.Cohorts.Any(x => x.CohortID == task.CohortID && DateTime.Now >= x.StartDate && DateTime.Now <= x.EndDate) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { return(task); } else { return(exceptionList); } } // End of ModifyTaskBLL
} // End of AddTaskTypeBLL /// <summary> /// Business logic for processing TaskType description change. /// </summary> /// <param name="taskType"></param> /// <returns></returns> internal object ModifyTaskTypeBLL(TaskTypeDTO taskType) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Due to the number of checks, this approach is more appropriate Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "Specified TypeID does not exist", !_context.TaskTypes.Any(x => x.TypeID == taskType.TypeID) }, { "description parameter cannot be empty", taskType.Description == null || taskType.Description.Trim() == string.Empty }, { "description must be unique", !string.IsNullOrEmpty(taskType.Description) && _context.TaskTypes.Any(x => x.Description.ToLower() == taskType.Description.Trim().ToLower() && x.TypeID != taskType.TypeID) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // Capitalise the first letter of the first word of the description string dbDescription = $"{taskType.Description.Trim().Substring(0, 1).ToUpper()}{taskType.Description.Trim().Substring(1)?.ToLower()}"; taskType.Description = dbDescription; return(taskType); } else { return(exceptionList); } } // End of ModifyTaskTypeBLL
} // End of ModifyTimesheetRecordBLL /// <summary> /// Business Logic for deleting an existing record /// </summary> /// <param name="recordID"></param> /// <param name="userClaims"></param> /// <returns></returns> internal object DeleteTimesheetRecordBLL(int recordID, ClaimsPrincipal userClaims) { // Check if the current user is a staff member (or Super Admin) bool isUserStaff = userClaims.IsInRole("Staff") || userClaims.IsInRole("SuperAdmin"); // Get the StudentID of the currrent user (or 0) int currentStudentID = isUserStaff ? 0 : _context.Users.Where(x => x.Email == userClaims.FindFirstValue("email")).Include(users => users.StudentData).FirstOrDefault()?.StudentData.StudentID ?? 0; // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "StudentID in the record cannot differ from the StudentID of the authenticated user", !(_context.Timesheets.Where(x => x.RecordID == recordID).First().StudentID == currentStudentID) || isUserStaff } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { return(recordID); } else { return(exceptionList); } } // End of TimesheetDeleteBLL
/// <summary> /// Business logic for creating staff records in database /// </summary> /// <param name="userID"></param> /// <param name="superUser"</param> /// <returns>BLL result object</returns> internal object AddStaffBLL(int userID, bool superUser) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "Specified userID does not exist", !_context.Users.Any(x => x.UserID == userID) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { StaffDTO newStaff = new StaffDTO { UserID = userID, SuperUser = superUser }; return(newStaff); } else { return(exceptionList); } } // End of AddStaffBLL
} // End of AddAttendanceBLL /// <summary> /// Business Logic for modifying Attendances table records /// </summary> /// <param name="attendance">AttendanceModDTO object with properties to modify</param> /// <param name="userClaims">ClaimsPrincipal object containing User Identity</param> /// <returns>object Exception or AttendanceModDTO</returns> internal object ModifyAttendanceBLL(AttendanceModDTO attendance, ClaimsPrincipal userClaims) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Due to the number of checks, this approach is more appropriate Dictionary<string, bool> exceptionTests = new Dictionary<string, bool>() { { "Specified RecordID does not exist", !_context.AttendanceRecords.Any(x => x.RecordID == attendance.RecordID) }, { "Specified AttendanceStateID does not exist", !_context.AttendanceStates.Any(x => x.StateID == attendance.AttendanceStateID) } }; foreach (KeyValuePair<string, bool> kvp in exceptionTests) { if (kvp.Value) exceptionList.AddExMessage(kvp.Key); } if (!exceptionList.HasExceptions) { return attendance; } else { return exceptionList; } } // End of ModifyAttendanceBLL
} // End of AddStaffBLL /// <summary> /// Business logic for modifying Staff records /// </summary> /// <param name="staff"></param> /// <returns></returns> internal object ModifyUserBLL(StaffDTO staff) { APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "Specified UserID does not exist", !_context.Users.Any(x => x.UserID == staff.UserID) }, { "Specified StaffID does not exist", !_context.Staff.Any(x => x.StaffID == staff.StaffID) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { return(staff); } else { return(exceptionList); } } // End of ModifyStaff
/// <summary> /// Business logic for adding Cohort records /// </summary> /// <param name="name"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <returns></returns> internal object AddCohortBLL(string name, DateTime startDate, DateTime endDate) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Check if the name has been supplied or if it's empty after trimming if (name == null || name.Trim() == string.Empty) { exceptionList.AddExMessage("Name parameter cannot be empty."); } else { // Check if a cohort with the same name exists in the database (trim + case insensitive) bool dbContainsName = _context.Cohorts.Where(x => x.Name.ToLower() == name.Trim().ToLower()).Count() > 0; if (dbContainsName) { exceptionList.AddExMessage("A cohort with the same name already exists in the database."); } // Check that the startDate is less than endDate bool datesConsistent = startDate < endDate; if (!datesConsistent) { exceptionList.AddExMessage("Start date must be before the end date, check for consistency."); } } if (!exceptionList.HasExceptions) { // New database name will be trimmed and in Proper Case. string dbName = String.Join(" ", name.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); Cohort newDbObject = new Cohort { Name = dbName, StartDate = startDate, EndDate = endDate }; return(newDbObject); } else { return(exceptionList); } } // End of AddCohort
} // End of StudentDetailBLL /// <summary> /// Business logic for adding Student records /// </summary> /// <param name="firstname"></param> /// <param name="lastname"></param> /// <param name="email"></param> /// <param name="active"></param> /// <param name="cohortID"></param> /// <param name="bearTracksID"></param> /// <param name="userIsSuperAdmin"></param> /// <returns></returns> internal object AddStudentBLL(string firstname, string lastname, string email, bool active, int cohortID, string bearTracksID, bool userIsSuperAdmin) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Email check regex in Dictionary below // Ref: https://stackoverflow.com/a/45177249/12802214 // Due to the number of checks, this approach is more appropriate Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "firstname parameter cannot be empty.", firstname == null || firstname.Trim() == string.Empty }, { "lastname parameter cannot be empty", lastname == null || lastname.Trim() == string.Empty }, { "Email needs to be a valid email address", email == null || !Regex.IsMatch(email, @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$") }, { "Email address needs to be unique in the database (student record already exists)", email != null && _context.Users.Any(x => x.Email == email) && _context.Students.Any(x => x.UserID == _context.Users.Where(y => y.Email == email).First().UserID) }, { "Email address domain not found in the list of valid domains", email != null && !APIConfig.Configuration.GetSection("ValidEmailDomains").GetChildren().ToArray().Select(x => x.Value).ToArray().Contains(email.Split("@")?[1] ?? "") }, { "Specified CohortID does not exist", !_context.Cohorts.Any(x => x.CohortID == cohortID) }, { "Specified cohort is inactive.", !(_context.Cohorts.Any(x => x.CohortID == cohortID && DateTime.Now >= x.StartDate && DateTime.Now <= x.EndDate) || userIsSuperAdmin) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // New database names will be trimmed and in Proper Case. string dbFirstname = String.Join(" ", firstname.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); string dbLastname = String.Join(" ", lastname.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); // Create a dictionary containing all data needed to create the user and pass back to API Target Dictionary <string, object> newDbObject = new Dictionary <string, object>() { { "Firstname", dbFirstname }, { "Lastname", dbLastname }, { "Email", email }, { "Active", active }, { "CohortID", cohortID }, { "BearTracksID", bearTracksID }, { "UserAlreadyInUsersTable", _context.Users.Any(x => x.Email == email) } }; return(newDbObject); } else { return(exceptionList); } } // End of AddStudent
} // End of GetTimesheetRecordBLL /// <summary> /// Business logic for processing Timesheet record addition /// </summary> /// <param name="timesheetRecord"></param> /// <param name="userClaims"></param> /// <returns></returns> internal object AddTimesheetRecordBLL(TimesheetDTO timesheetRecord, ClaimsPrincipal userClaims) { // Check if the current user is a staff member (or Super Admin) bool isUserStaff = userClaims.IsInRole("Staff") || userClaims.IsInRole("SuperAdmin"); // Get the StudentID of the currrent user (or 0) int currentStudentID = isUserStaff ? 0 : _context.Users.Where(x => x.Email == userClaims.FindFirstValue("email")).Include(users => users.StudentData).FirstOrDefault()?.StudentData.StudentID ?? 0; if (timesheetRecord.StudentID == 0 && !isUserStaff) { timesheetRecord.StudentID = currentStudentID; } // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "Specified StudentID does not exist", !_context.Students.Any(x => x.StudentID == timesheetRecord.StudentID) }, { "StudentID cannot differ from the authenticated user", !(timesheetRecord.StudentID == currentStudentID || isUserStaff) }, { "Student account matching the StudentID must be active", !(_context.Students.Where(x => x.StudentID == timesheetRecord.StudentID).Include(student => student.UserData).FirstOrDefault().UserData.Active || isUserStaff) }, { "Specified AssignmentID does not exist", !_context.Tasks.Any(x => x.TaskID == timesheetRecord.AssignmentID) }, { "Specified date is older than 7 days", ((DateTime.Today - timesheetRecord.Date).Days > 7) && !isUserStaff }, { "Specified date cannot be in the future", !(timesheetRecord.Date <= DateTime.Today) }, { "TimeAllocation has to be a positive number, or zero", !(timesheetRecord.TimeAllocation >= 0) }, { "TimeAllocation has to be less than or equal to 18h", !(timesheetRecord.TimeAllocation <= 18) } // { "Only one record per AssignmentID per date is allowed", _context.Timesheets.Any(x => x.Date == timesheetRecord.Date && x.AssignmentID == timesheetRecord.AssignmentID && x.StudentID == timesheetRecord.StudentID) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // Round the TimeAlllocation to 15 min (0.25h) // Ref: https://stackoverflow.com/a/2826278/12802214 timesheetRecord.TimeAllocation = Math.Round(timesheetRecord.TimeAllocation * 4, MidpointRounding.AwayFromZero) / 4; return(timesheetRecord); } else { return(exceptionList); } } // End of AddTimesheetRecordBLL
} // End of ModifyAttendanceBLL /// <summary> /// Business Logic for processing Get requests for records in the attendance table /// </summary> /// <param name="studentID"></param> /// <param name="attendanceStateID"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="userClaims"></param> /// <returns></returns> internal object GetAttendanceBLL(int studentID, int attendanceStateID, DateTime startDate, DateTime endDate, ClaimsPrincipal userClaims) { // Check if the current user is a staff member (or Super Admin) bool isUserStaff = userClaims.IsInRole("Staff") || userClaims.IsInRole("SuperAdmin"); // Get the StudentID of the currrent user (or null) int currentStudentID = isUserStaff? 0 : _context.Users.Where(x => x.Email == userClaims.FindFirstValue("email")).Include(users => users.StudentData).FirstOrDefault()?.StudentData.StudentID ?? 0; // Apply defaults if (startDate == DateTime.MinValue) startDate = DateTime.Today.AddDays(-7); if (endDate == DateTime.MinValue) endDate = DateTime.Today; if (studentID == 0) studentID = currentStudentID; // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Due to the number of checks, this approach is more appropriate Dictionary<string, bool> exceptionTests = new Dictionary<string, bool>() { { "StudentID has to match the current user StudentID", !(studentID == currentStudentID || isUserStaff) }, { "Start date cannot be after the end date", !(startDate <= endDate) }, { "Invalid attendanceStateID specified", !(_context.AttendanceStates.Any(x => x.StateID == attendanceStateID) || attendanceStateID == 0) } }; foreach (KeyValuePair<string, bool> kvp in exceptionTests) { if (kvp.Value) exceptionList.AddExMessage(kvp.Key); } if (!exceptionList.HasExceptions) { // Create a dictionary containing all data needed to create the user and pass back to API Target Dictionary<string, object> getParams = new Dictionary<string, object>() { { "StudentID", studentID }, { "AttendanceStateID", attendanceStateID}, { "StartDate", startDate}, { "EndDate", endDate} }; return getParams; } else { return exceptionList; } }// End of GetAttendanceBLL
/// <summary> /// Business logic for creating users in database /// </summary> /// <param name="firstname"></param> /// <param name="lastname"></param> /// <param name="email"></param> /// <param name="active"></param> /// <returns></returns> internal object AddUserBLL(string firstname, string lastname, string email, bool active) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Email check regex in Dictionary below // Ref: https://stackoverflow.com/a/45177249/12802214 Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "firstname parameter cannot be empty.", firstname == null || firstname.Trim() == string.Empty }, { "lastname parameter cannot be empty", lastname == null || lastname.Trim() == string.Empty }, { "Email needs to be a valid email address", email == null || !Regex.IsMatch(email, @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$") }, { "Email address needs to be unique in the database (user record already exists)", email != null && _context.Users.Any(x => x.Email == email) && _context.Students.Any(x => x.UserID == _context.Users.Where(y => y.Email == email).First().UserID) }, { "Email address domain not found in the list of valid domains", email != null && !APIConfig.Configuration.GetSection("ValidEmailDomains").GetChildren().ToArray().Select(x => x.Value).ToArray().Contains(email.Split("@")?[1] ?? "") } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // New database names will be trimmed and in Proper Case. string dbFirstname = String.Join(" ", firstname.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); string dbLastname = String.Join(" ", lastname.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); UserDTO newUser = new UserDTO { Firstname = dbFirstname, Lastname = dbLastname, Email = email, Active = active }; return(newUser); } else { return(exceptionList); } } // End of AddUserBLL
/// <summary> /// Business logic for retrieving Notice records /// </summary> /// <param name="noticeID"></param> /// <param name="cohortID"></param> /// <param name="staffID"></param> /// <param name="validFrom"></param> /// <param name="isUserStaff"></param> /// <returns></returns> internal object GetNoticeBLL(int noticeID, int cohortID, int staffID, DateTime validFrom, bool isUserStaff) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "noticeID must be valid", noticeID != 0 && !_context.Notices.Any(x => x.NoticeID == noticeID) }, { "cohortID must be valid", cohortID != 0 && !_context.Cohorts.Any(x => x.CohortID == cohortID) }, { "staffID must be valid", staffID != 0 && !_context.Staff.Any(x => x.StaffID == staffID) }, { "validFrom date cannot be in the future", !(validFrom <= DateTime.Today) && !isUserStaff } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // Apply defaults if (validFrom == DateTime.MinValue) { validFrom = _context.Cohorts.Where(x => x.CohortID == cohortID).First().StartDate; } NoticeDTO getParams = new NoticeDTO { NoticeID = noticeID, CohortID = cohortID, StaffID = staffID, ValidFrom = validFrom }; return(getParams); } else { return(exceptionList); } } // End of GetNoticeBLL
} // End of AddStudent /// <summary> /// Business logic for modifying Student records /// </summary> /// <param name="student"></param> /// <param name="userIsSuperAdmin"></param> /// <returns></returns> internal object ModifyStudentBLL(StudentModDTO student, bool userIsSuperAdmin) { // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Email check regex in Dictionary below // Ref: https://stackoverflow.com/a/45177249/12802214 // Check is virtually identical to that of the AddStudent method, except for the e-mail address unique check Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "firstname parameter cannot be empty.", student.Firstname == null || student.Firstname.Trim() == string.Empty }, { "lastname parameter cannot be empty", student.Lastname == null || student.Lastname.Trim() == string.Empty }, { "Email needs to be a valid email address", student.Email == null || !Regex.IsMatch(student.Email, @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$") }, { "Email address needs to be unique in the database (student record with that email already exists)", student.Email != null && _context.Users.Where(x => x.Email == student.Email).Include(student => student.StudentData).Any(x => x.StudentData.StudentID != student.StudentID) }, { "Email address domain not found in the list of valid domains", student.Email != null && !APIConfig.Configuration.GetSection("ValidEmailDomains").GetChildren().ToArray().Select(x => x.Value).ToArray().Contains(student.Email.Split("@")?[1] ?? "") }, { "Specified CohortID does not exist", !_context.Cohorts.Any(x => x.CohortID == student.CohortID) }, { "Specified cohort is inactive.", !(_context.Cohorts.Any(x => x.CohortID == student.CohortID && DateTime.Now >= x.StartDate && DateTime.Now <= x.EndDate) || userIsSuperAdmin) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { // New database names will be trimmed and in Proper Case. string dbFirstname = String.Join(" ", student.Firstname.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); string dbLastname = String.Join(" ", student.Lastname.Trim().Split(" ").Select(x => $"{x.Substring(0, 1).ToUpper()}{x.Substring(1)?.ToLower()}").ToArray()); // Create a dictionary containing all data needed to create the user and pass back to API Target. StudentModDTO modifiedDbObject = new StudentModDTO { StudentID = student.StudentID, Firstname = dbFirstname, Lastname = dbLastname, Email = student.Email, Active = student.Active, CohortID = student.CohortID, BearTracksID = student.BearTracksID }; return(modifiedDbObject); } else { return(exceptionList); } } // End of ModifyStudent
/// <summary> /// Business logic for adding an attendance record to the database /// </summary> /// <param name="attendance"></param> /// <param name="userClaims"></param> /// <returns>object Exception() or object attendanceDTO</returns> internal object AddAttendanceBLL(AttendanceDTO attendance, ClaimsPrincipal userClaims) { // Get the StaffID of the currently logged in Staff member int loggedInStaffID = _context.Users.Where(x => x.Email == userClaims.FindFirst("Email").Value).Include(user => user.StaffData).Select(x => x.StaffData.StaffID).First(); int studentUserID = _context.Students.Where(x => x.StudentID == attendance.StudentID).Select(x => x.UserID).First(); // Is the user Super Admin? bool userIsSuperAdmin = userClaims.IsInRole("SuperAdmin"); // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Due to the number of checks, this approach is more appropriate Dictionary<string, bool> exceptionTests = new Dictionary<string, bool>() { { "Specified StudentID does not exist", !_context.Students.Any(x => x.StudentID == attendance.StudentID) }, { "Specified AttendanceStateID does not exist", !_context.AttendanceStates.Any(x => x.StateID == attendance.AttendanceStateID) }, { "Specified StaffID does not exist", !_context.Staff.Any(x => x.StaffID == attendance.StaffID) }, { "Specified StaffID does not match current user credentials", !(_context.Staff.Any(x => x.StaffID == attendance.StaffID) && loggedInStaffID == attendance.StaffID) }, { "Duplicate record exists in the database (StudentID, Date)", _context.AttendanceRecords.Any(x => x.StudentID == attendance.StudentID && x.Date == attendance.Date) }, { "Specified attendance record cannot be added as the specified date is more than 3 days old", !(((DateTime.Today - attendance.Date.Date).Days <= 3) || userIsSuperAdmin) }, { "Specified student is inactive.", !(_context.Students.Where(x => x.StudentID == attendance.StudentID).Include(student => student.UserData).Select(x => x.UserData.Active).First() || userIsSuperAdmin) } }; foreach (KeyValuePair<string, bool> kvp in exceptionTests) { if (kvp.Value) exceptionList.AddExMessage(kvp.Key); } if (!exceptionList.HasExceptions) { return attendance; } else { return exceptionList; } } // End of AddAttendanceBLL
/// <summary> /// Business logic for retrieving Timesheet records /// </summary> /// <param name="recordID"></param> /// <param name="studentID"></param> /// <param name="assignmentID"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="userClaims"></param> /// <returns></returns> internal object GetTimesheetRecordBLL(int recordID, int studentID, int unitID, int typeID, int assignmentID, int cohortID, DateTime startDate, DateTime endDate, ClaimsPrincipal userClaims) { // Check if the current user is a staff member (or Super Admin) bool isUserStaff = userClaims.IsInRole("Staff") || userClaims.IsInRole("SuperAdmin"); // Get the StudentID of the currrent user (or null) int currentStudentID = isUserStaff ? 0 : _context.Users.Where(x => x.Email == userClaims.FindFirstValue("email")).Include(users => users.StudentData).FirstOrDefault()?.StudentData.StudentID ?? 0; // Apply defaults if (startDate == DateTime.MinValue) { startDate = DateTime.Today; } if (endDate == DateTime.MinValue) { endDate = DateTime.Today; } if (!isUserStaff) { studentID = currentStudentID; } // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "recordID must be valid", recordID != 0 && !_context.Timesheets.Any(x => x.RecordID == recordID) }, { "cohortID must be valid", cohortID != 0 && !_context.Cohorts.Any(x => x.CohortID == cohortID) }, { "unitID must be valid", unitID != 0 && !_context.Units.Any(x => x.UnitID == unitID) }, { "typeID must be valid", typeID != 0 && !_context.TaskTypes.Any(x => x.TypeID == typeID) }, { "assignmentID must be valid", assignmentID != 0 && !_context.Tasks.Any(x => x.TaskID == assignmentID) }, { "studentID must be valid", studentID != 0 && !_context.Students.Any(x => x.StudentID == studentID) }, { "startDate cannot be after the endDate", !(startDate <= endDate) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { TimesheetGetDTO getParams = new TimesheetGetDTO { RecordID = recordID, StudentID = studentID, CohortID = cohortID, AssignmentID = assignmentID, TypeID = typeID, UnitID = unitID, StartDate = startDate, EndDate = endDate }; return(getParams); } else { return(exceptionList); } } // End of GetTimesheetRecordBLL
} // End of ModifyTaskBLL /// <summary> /// Business logic for retrieving Task records /// </summary> /// <param name="taskID"></param> /// <param name="cohortID"></param> /// <param name="typeID"></param> /// <param name="unitID"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="userClaims"></param> /// <returns></returns> internal object GetTaskBLL(int taskID, int cohortID, int typeID, int unitID, DateTime startDate, DateTime endDate, ClaimsPrincipal userClaims) { // Check if the current user is a staff member (or Super Admin) bool isUserStaff = userClaims.IsInRole("Staff") || userClaims.IsInRole("SuperAdmin"); // Get the CohortID of the currrent user (or null) int currentCohortID = isUserStaff ? 0 : _context.Users.Where(x => x.Email == userClaims.FindFirstValue("email")).Include(users => users.StudentData).FirstOrDefault()?.StudentData.CohortID ?? 0; // Apply defaults if (startDate == DateTime.MinValue) { startDate = DateTime.Today.AddDays(-14); } if (endDate == DateTime.MinValue) { endDate = DateTime.Today.AddDays(7); } // Do not allow students to see future assignments if (startDate > DateTime.Today && !isUserStaff) { startDate = DateTime.Today; } if (cohortID == 0) { cohortID = currentCohortID; } // Create a new APIException object to store possible exceptions as checks are performed. APIException exceptionList = new APIException(); // Due to the number of checks, this approach is more appropriate Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>() { { "cohortID has to match the current user's CohortID", !(cohortID == currentCohortID || isUserStaff) }, { "taskID must be valid.", taskID != 0 && !_context.Tasks.Any(x => x.TaskID == taskID) }, { "cohortID must be valid.", cohortID != 0 && !_context.Cohorts.Any(x => x.CohortID == cohortID) }, { "typeID must be valid.", typeID != 0 && !_context.TaskTypes.Any(x => x.TypeID == typeID) }, { "unitID must be valid.", unitID != 0 && !_context.Units.Any(x => x.UnitID == unitID) }, { "Start date cannot be after the end date", !(startDate <= endDate) } }; foreach (KeyValuePair <string, bool> kvp in exceptionTests) { if (kvp.Value) { exceptionList.AddExMessage(kvp.Key); } } if (!exceptionList.HasExceptions) { TaskDTO getParams = new TaskDTO { TaskID = taskID, CohortID = cohortID, TypeID = typeID, UnitID = unitID, StartDate = startDate, EndDate = endDate }; return(getParams); } else { return(exceptionList); } }// End of GetTaskBLL