public async Task <ActionResult <List <AuditDto> > > ViewRoleHistory(Guid sheriffId) { var sheriff = await SheriffService.GetSheriff(sheriffId, null); if (sheriff == null) { return(NotFound(CouldNotFindSheriffError)); } if (!PermissionDataFiltersExtensions.HasAccessToLocation(User, Db, sheriff.HomeLocationId)) { return(Forbid()); } var userRoleIds = Db.UserRole.AsNoTracking().Where(ur => ur.UserId == sheriffId).Select(ur => ur.Id); var roleHistory = Db.Audit.AsNoTracking().Include(a => a.CreatedBy).Where(e => e.TableName == "UserRole" && userRoleIds.Contains(e.KeyValues.RootElement.GetProperty("Id") .GetInt32())) .ToList(); //Have to select, because we have adapt ignore on these properties. return(Ok(roleHistory.Select(s => { var audit = s.Adapt <AuditDto>(); audit.CreatedBy = s.CreatedBy.Adapt <SheriffDto>(); audit.CreatedOn = s.CreatedOn; audit.CreatedById = s.CreatedById; return audit; }))); }
public async Task <ActionResult <SheriffDto> > UploadPhoto(Guid?id, string badgeNumber, IFormFile file) { await CheckForAccessToSheriffByLocation(id, badgeNumber); if (file.Length == 0) { return(BadRequest("File length = 0")); } if (file.Length >= _uploadPhotoSizeLimitKB * 1024) { return(BadRequest($"File length: {file.Length/1024} KB, Maximum upload size: {_uploadPhotoSizeLimitKB} KB")); } await using var ms = new MemoryStream(); await file.CopyToAsync(ms); var fileBytes = ms.ToArray(); if (!fileBytes.IsImage()) { return(BadRequest("The uploaded file was not a valid GIF/JPEG/PNG.")); } var sheriff = await SheriffService.UpdateSheriffPhoto(id, badgeNumber, fileBytes); return(Ok(sheriff.Adapt <SheriffDto>())); }
private async Task <List <ShiftConflict> > CheckSheriffEventsOverlap(List <Shift> shifts) { var sheriffEventConflicts = new List <ShiftConflict>(); foreach (var shift in shifts) { var locationId = shift.LocationId; var sheriffs = await SheriffService.GetSheriffsForShiftAvailability(locationId, shift.StartDate, shift.EndDate, shift.SheriffId); var sheriff = sheriffs.FirstOrDefault(); sheriff.ThrowBusinessExceptionIfNull($"Couldn't find active {nameof(Sheriff)}:{shift.SheriffId}, they might not be active in location for the shift."); var validationErrors = new List <string>(); validationErrors.AddRange(sheriff !.AwayLocation.Where(aw => aw.LocationId != shift.LocationId).Select(aw => PrintSheriffEventConflict <SheriffAwayLocation>(aw.Sheriff, aw.StartDate, aw.EndDate, aw.Timezone))); validationErrors.AddRange(sheriff.Leave.Select(aw => PrintSheriffEventConflict <SheriffLeave>(aw.Sheriff, aw.StartDate, aw.EndDate, aw.Timezone))); validationErrors.AddRange(sheriff.Training.Select(aw => PrintSheriffEventConflict <SheriffTraining>(aw.Sheriff, aw.StartDate, aw.EndDate, aw.Timezone))); if (validationErrors.Any()) { sheriffEventConflicts.Add(new ShiftConflict { Shift = shift, ConflictMessages = validationErrors }); } } return(sheriffEventConflicts); }
public async Task <ActionResult <SheriffActingRankDto> > UpdateSheriffActingRank(SheriffActingRankDto sheriffActingRankDto, bool overrideConflicts = false) { var sheriffActingRank = sheriffActingRankDto.Adapt <SheriffActingRank>(); var updatedSheriffActingRank = await SheriffService.UpdateSheriffActingRank(DutyRosterService, ShiftService, sheriffActingRank, overrideConflicts); return(Ok(updatedSheriffActingRank.Adapt <SheriffActingRankDto>())); }
public async Task <List <ShiftAvailability> > GetShiftAvailability(int locationId, DateTimeOffset start, DateTimeOffset end) { var sheriffs = await SheriffService.GetSheriffsForShiftAvailability(locationId, start, end); var shiftsForSheriffs = await GetShiftsForSheriffs(sheriffs.Select(s => s.Id), start, end); var sheriffEventConflicts = new List <ShiftAvailabilityConflict>(); sheriffs.ForEach(sheriff => { sheriffEventConflicts.AddRange(sheriff.AwayLocation.Select(s => new ShiftAvailabilityConflict { Conflict = ShiftConflictType.AwayLocation, SheriffId = sheriff.Id, Start = s.StartDate, End = s.EndDate, LocationId = s.LocationId, Location = s.Location })); sheriffEventConflicts.AddRange(sheriff.Leave.Select(s => new ShiftAvailabilityConflict { Conflict = ShiftConflictType.Leave, SheriffId = sheriff.Id, Start = s.StartDate, End = s.EndDate })); sheriffEventConflicts.AddRange(sheriff.Training.Select(s => new ShiftAvailabilityConflict { Conflict = ShiftConflictType.Training, SheriffId = sheriff.Id, Start = s.StartDate, End = s.EndDate })); }); var existingShiftConflicts = shiftsForSheriffs.Select(s => new ShiftAvailabilityConflict { Conflict = ShiftConflictType.Scheduled, SheriffId = s.SheriffId, Location = s.Location, LocationId = s.LocationId, Start = s.StartDate, End = s.EndDate, ShiftId = s.Id }); var allShiftConflicts = sheriffEventConflicts.Concat(existingShiftConflicts).ToList(); return(sheriffs.SelectToList(s => new ShiftAvailability { Start = start, End = end, Sheriff = s, SheriffId = s.Id, Conflicts = allShiftConflicts.WhereToList(asc => asc.SheriffId == s.Id) }) .OrderBy(s => s.Sheriff.LastName) .ThenBy(s => s.Sheriff.FirstName) .ToList()); }
public async Task <ActionResult <SheriffDto> > UpdateSheriffHomeLocation(Guid id, int locationId) { await CheckForAccessToSheriffByLocation(id); await SheriffService.UpdateSheriffHomeLocation(id, locationId); return(NoContent()); }
public SheriffController(SheriffService sheriffService, DutyRosterService dutyRosterService, ShiftService shiftService, UserService userUserService, IConfiguration configuration, SheriffDbContext db) : base(userUserService) { SheriffService = sheriffService; ShiftService = shiftService; DutyRosterService = dutyRosterService; Db = db; _uploadPhotoSizeLimitKB = Convert.ToInt32(configuration.GetNonEmptyValue("UploadPhotoSizeLimitKB")); }
public async Task <ActionResult> RemoveSheriffTraining(int id, string expiryReason) { await CheckForAccessToSheriffByLocation <SheriffTraining>(id); await SheriffService.RemoveSheriffTraining(id, expiryReason); return(NoContent()); }
public async Task <ActionResult <SheriffLeaveDto> > AddSheriffLeave(SheriffLeaveDto sheriffLeaveDto) { await CheckForAccessToSheriffByLocation(sheriffLeaveDto.SheriffId); var sheriffLeave = sheriffLeaveDto.Adapt <SheriffLeave>(); var createdSheriffLeave = await SheriffService.AddSheriffLeave(sheriffLeave); return(Ok(createdSheriffLeave.Adapt <SheriffLeaveDto>())); }
public async Task <ActionResult <SheriffLeaveDto> > UpdateSheriffLeave(SheriffLeaveDto sheriffLeaveDto) { await CheckForAccessToSheriffByLocation <SheriffLeave>(sheriffLeaveDto.Id); var sheriffLeave = sheriffLeaveDto.Adapt <SheriffLeave>(); var updatedSheriffLeave = await SheriffService.UpdateSheriffLeave(sheriffLeave); return(Ok(updatedSheriffLeave.Adapt <SheriffLeaveDto>())); }
public async Task <ActionResult <SheriffTrainingDto> > AddSheriffTraining(SheriffTrainingDto sheriffTrainingDto) { await CheckForAccessToSheriffByLocation(sheriffTrainingDto.SheriffId); var sheriffTraining = sheriffTrainingDto.Adapt <SheriffTraining>(); var createdSheriffTraining = await SheriffService.AddSheriffTraining(sheriffTraining); return(Ok(createdSheriffTraining.Adapt <SheriffTrainingDto>())); }
public async Task <ActionResult <SheriffTrainingDto> > UpdateSheriffTraining(SheriffTrainingDto sheriffTrainingDto) { await CheckForAccessToSheriffByLocation <SheriffTraining>(sheriffTrainingDto.Id); var sheriffTraining = sheriffTrainingDto.Adapt <SheriffTraining>(); var updatedSheriffTraining = await SheriffService.UpdateSheriffTraining(sheriffTraining); return(Ok(updatedSheriffTraining.Adapt <SheriffTrainingDto>())); }
public async Task <ActionResult <SheriffTrainingDto> > AddSheriffTraining(SheriffTrainingDto sheriffTrainingDto, bool overrideConflicts = false) { await CheckForAccessToSheriffByLocation(sheriffTrainingDto.SheriffId); var sheriffTraining = sheriffTrainingDto.Adapt <SheriffTraining>(); var createdSheriffTraining = await SheriffService.AddSheriffTraining(DutyRosterService, ShiftService, sheriffTraining, overrideConflicts); return(Ok(createdSheriffTraining.Adapt <SheriffTrainingDto>())); }
public async Task <ActionResult <SheriffLeaveDto> > UpdateSheriffLeave(SheriffLeaveDto sheriffLeaveDto, bool overrideConflicts = false) { await CheckForAccessToSheriffByLocation <SheriffLeave>(sheriffLeaveDto.Id); var sheriffLeave = sheriffLeaveDto.Adapt <SheriffLeave>(); var updatedSheriffLeave = await SheriffService.UpdateSheriffLeave(DutyRosterService, ShiftService, sheriffLeave, overrideConflicts); return(Ok(updatedSheriffLeave.Adapt <SheriffLeaveDto>())); }
public async Task <ActionResult <SheriffAwayLocationDto> > UpdateSheriffAwayLocation(SheriffAwayLocationDto sheriffAwayLocationDto) { await CheckForAccessToSheriffByLocation <SheriffAwayLocation>(sheriffAwayLocationDto.Id); var sheriffAwayLocation = sheriffAwayLocationDto.Adapt <SheriffAwayLocation>(); var updatedSheriffAwayLocation = await SheriffService.UpdateSheriffAwayLocation(sheriffAwayLocation); return(Ok(updatedSheriffAwayLocation.Adapt <SheriffAwayLocationDto>())); }
public async Task <ActionResult <SheriffDto> > UpdateSheriff(SheriffDto sheriffDto) { await CheckForAccessToSheriffByLocation(sheriffDto.Id); var sheriff = sheriffDto.Adapt <Sheriff>(); sheriff = await SheriffService.UpdateSheriff(sheriff); return(Ok(sheriff.Adapt <SheriffDto>())); }
public async Task <ActionResult <SheriffDto> > GetSelfSheriff() { var sheriff = await SheriffService.GetFilteredSheriffForTeams(User.CurrentUserId()); if (sheriff == null) { return(NotFound(CouldNotFindSheriffError)); } return(Ok(sheriff.Adapt <SheriffDto>())); }
public async Task <ImportedShifts> ImportWeeklyShifts(int locationId, DateTimeOffset start) { var location = Db.Location.FirstOrDefault(l => l.Id == locationId); location.ThrowBusinessExceptionIfNull($"Couldn't find {nameof(Location)} with id: {locationId}."); var timezone = location?.Timezone; timezone.GetTimezone().ThrowBusinessExceptionIfNull("Timezone was invalid."); //We need to adjust to their start of the week, because it can differ depending on the TZ! var targetStartDate = start.ConvertToTimezone(timezone); var targetEndDate = targetStartDate.TranslateDateIfDaylightSavings(timezone, 7); var sheriffsAvailableAtLocation = await SheriffService.GetSheriffsForShiftAvailability(locationId, targetStartDate, targetEndDate); var sheriffIds = sheriffsAvailableAtLocation.SelectDistinctToList(s => s.Id); var shiftsToImport = Db.Shift .Include(s => s.Location) .Include(s => s.Sheriff) .AsNoTracking() .Where(s => s.LocationId == locationId && s.ExpiryDate == null && s.StartDate < targetEndDate && targetStartDate < s.EndDate && s.SheriffId != null && sheriffIds.Contains(s.SheriffId.Value)); var importedShifts = await shiftsToImport.Select(shift => Db.DetachedClone(shift)).ToListAsync(); foreach (var shift in importedShifts) { shift.SheriffId = shift.SheriffId; shift.StartDate = shift.StartDate.TranslateDateIfDaylightSavings(timezone, 7); shift.EndDate = shift.EndDate.TranslateDateIfDaylightSavings(timezone, 7); } var overlaps = await GetShiftConflicts(importedShifts); var filteredImportedShifts = importedShifts.WhereToList(s => overlaps.All(o => o.Shift.Id != s.Id) && !overlaps.Any(ts => s.Id != ts.Shift.Id && ts.Shift.StartDate < s.EndDate && s.StartDate < ts.Shift.EndDate && ts.Shift.SheriffId == s.SheriffId)); filteredImportedShifts.ForEach(s => s.Id = 0); await Db.Shift.AddRangeAsync(filteredImportedShifts); await Db.SaveChangesAsync(); return(new ImportedShifts { ConflictMessages = overlaps.SelectMany(o => o.ConflictMessages).ToList(), Shifts = filteredImportedShifts }); }
public async Task <ActionResult <SheriffDto> > UpdateSheriff(SheriffWithIdirDto updateSheriff) { await CheckForAccessToSheriffByLocation(updateSheriff.Id); var canEditIdir = User.HasPermission(Permission.EditIdir); var sheriff = updateSheriff.Adapt <Sheriff>(); sheriff = await SheriffService.UpdateSheriff(sheriff, canEditIdir); return(Ok(sheriff.Adapt <SheriffDto>())); }
private async Task CheckForAccessToSheriffByLocation(Guid?id, string badgeNumber = null) { var savedSheriff = await SheriffService.GetSheriff(id, badgeNumber); if (savedSheriff == null) { throw new NotFoundException(CouldNotFindSheriffError); } if (!PermissionDataFiltersExtensions.HasAccessToLocation(User, Db, savedSheriff.HomeLocationId)) { throw new NotAuthorizedException(); } }
public async Task <ActionResult <SheriffDto> > AddSheriff(CreateSheriffDto sheriffDto) { if (!PermissionDataFiltersExtensions.HasAccessToLocation(User, Db, sheriffDto.HomeLocationId)) { return(Forbid()); } var sheriff = sheriffDto.Adapt <Sheriff>(); sheriff = await SheriffService.AddSheriff(sheriff); return(Ok(sheriff.Adapt <SheriffDto>())); }
public async Task <ActionResult <SheriffDto> > GetSheriffForTeam(Guid id) { var sheriff = await SheriffService.GetFilteredSheriffForTeams(id); if (sheriff == null) { return(NotFound(CouldNotFindSheriffError)); } if (!PermissionDataFiltersExtensions.HasAccessToLocation(User, Db, sheriff.HomeLocationId)) { return(Forbid()); } return(Ok(sheriff.Adapt <SheriffDto>())); }
private async Task <List <ShiftConflict> > CheckSheriffEventsOverlap(List <Shift> shifts) { var sheriffEventConflicts = new List <ShiftConflict>(); foreach (var shift in shifts) { var locationId = shift.LocationId; var sheriffs = await SheriffService.GetSheriffsForShiftAvailabilityForLocation(locationId, shift.StartDate, shift.EndDate, shift.SheriffId); var sheriff = sheriffs.FirstOrDefault(); var validationErrors = new List <string>(); if (sheriff == null) { var unavailableSheriff = await Db.Sheriff.AsNoTracking().FirstOrDefaultAsync(s => s.Id == shift.SheriffId); validationErrors.Add($"{unavailableSheriff?.LastName}, {unavailableSheriff?.FirstName} is not active in this location for {shift.StartDate.ConvertToTimezone(shift.Timezone).PrintFormatDate()} {shift.StartDate.ConvertToTimezone(shift.Timezone).PrintFormatTime(shift.Timezone)} to {shift.EndDate.ConvertToTimezone(shift.Timezone).PrintFormatTime(shift.Timezone)}"); } else { validationErrors.AddRange(sheriff !.AwayLocation.Where(aw => aw.LocationId != shift.LocationId) .Select(aw => PrintSheriffEventConflict <SheriffAwayLocation>(aw.Sheriff, aw.StartDate, aw.EndDate, aw.Timezone))); validationErrors.AddRange(sheriff.Leave.Select(aw => PrintSheriffEventConflict <SheriffLeave>( aw.Sheriff, aw.StartDate, aw.EndDate, aw.Timezone))); validationErrors.AddRange(sheriff.Training.Select(aw => PrintSheriffEventConflict <SheriffTraining>( aw.Sheriff, aw.StartDate, aw.EndDate, aw.Timezone))); } if (validationErrors.Any()) { sheriffEventConflicts.Add(new ShiftConflict { Shift = shift, ConflictMessages = validationErrors }); } } return(sheriffEventConflicts); }
public SheriffControllerTests() : base(false) { var environment = new EnvironmentBuilder("LocationServicesClient:Username", "LocationServicesClient:Password", "LocationServicesClient:Url"); var httpContextAccessor = new HttpContextAccessor { HttpContext = HttpResponseTest.SetupHttpContext() }; var sheriffService = new SheriffService(Db, environment.Configuration, httpContextAccessor); var shiftService = new ShiftService(Db, sheriffService, environment.Configuration); var dutyRosterService = new DutyRosterService(Db, environment.Configuration, shiftService, environment.LogFactory.CreateLogger <DutyRosterService>()); _controller = new SheriffController(sheriffService, dutyRosterService, shiftService, new UserService(Db), environment.Configuration, Db) { ControllerContext = HttpResponseTest.SetupMockControllerContext() }; }
public async Task <ActionResult> RemoveSheriffTraining(int id, string expiryReason) { await CheckForAccessToSheriffByLocation <SheriffTraining>(id); if (!User.HasPermission(Permission.RemovePastTraining)) { var sheriffTraining = Db.SheriffTraining.AsNoTracking().FirstOrDefault(st => st.Id == id); if (sheriffTraining?.EndDate <= DateTimeOffset.UtcNow) { throw new BusinessLayerException("No permission to remove training that has completed."); } } await SheriffService.RemoveSheriffTraining(id, expiryReason); return(NoContent()); }
private async Task CheckForAccessToSheriffByLocation <T>(int id) where T : SheriffEvent { var sheriffEvent = await SheriffService.GetSheriffEvent <T>(id); if (sheriffEvent == null) { throw new NotFoundException(CouldNotFindSheriffEventError); } var savedSheriff = await SheriffService.GetSheriff(sheriffEvent.SheriffId, null); if (savedSheriff == null) { throw new NotFoundException(CouldNotFindSheriffError); } if (!PermissionDataFiltersExtensions.HasAccessToLocation(User, Db, savedSheriff.HomeLocationId)) { throw new NotAuthorizedException(); } }
public async Task <ActionResult <SheriffTrainingDto> > UpdateSheriffTraining(SheriffTrainingDto sheriffTrainingDto, bool overrideConflicts = false) { await CheckForAccessToSheriffByLocation <SheriffTraining>(sheriffTrainingDto.Id); var sheriffTraining = sheriffTrainingDto.Adapt <SheriffTraining>(); if (!User.HasPermission(Permission.EditPastTraining)) { var savedSheriffTraining = Db.SheriffTraining.AsNoTracking().FirstOrDefault(st => st.Id == sheriffTrainingDto.Id); if (savedSheriffTraining?.EndDate <= DateTimeOffset.UtcNow) { throw new BusinessLayerException("No permission to edit training that has completed."); } } var updatedSheriffTraining = await SheriffService.UpdateSheriffTraining(DutyRosterService, ShiftService, sheriffTraining, overrideConflicts); return(Ok(updatedSheriffTraining.Adapt <SheriffTrainingDto>())); }
public async Task <ActionResult <SheriffWithIdirDto> > GetSheriffForTeam(Guid id) { var sheriff = await SheriffService.GetFilteredSheriffForTeams(id); if (sheriff == null) { return(NotFound(CouldNotFindSheriffError)); } if (!PermissionDataFiltersExtensions.HasAccessToLocation(User, Db, sheriff.HomeLocationId)) { return(Forbid()); } var sheriffDto = sheriff.Adapt <SheriffWithIdirDto>(); //Prevent exposing Idirs to regular users. sheriffDto.IdirName = User.HasPermission(Permission.EditIdir) ? sheriff.IdirName : null; return(Ok(sheriffDto)); }
public async Task <ActionResult <SheriffDto> > GetSheriffsForTeams() { var sheriffs = await SheriffService.GetFilteredSheriffsForTeams(); return(Ok(sheriffs.Adapt <List <SheriffDto> >())); }
public async Task <IActionResult> GetPhoto(Guid id) => File(await SheriffService.GetPhoto(id), "image/jpeg");