Example #1
0
        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;
            })));
        }
Example #2
0
        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);
        }
Example #4
0
        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());
        }
Example #6
0
        public async Task <ActionResult <SheriffDto> > UpdateSheriffHomeLocation(Guid id, int locationId)
        {
            await CheckForAccessToSheriffByLocation(id);

            await SheriffService.UpdateSheriffHomeLocation(id, locationId);

            return(NoContent());
        }
Example #7
0
 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"));
 }
Example #8
0
        public async Task <ActionResult> RemoveSheriffTraining(int id, string expiryReason)
        {
            await CheckForAccessToSheriffByLocation <SheriffTraining>(id);

            await SheriffService.RemoveSheriffTraining(id, expiryReason);

            return(NoContent());
        }
Example #9
0
        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>()));
        }
Example #10
0
        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>()));
        }
Example #11
0
        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>()));
        }
Example #12
0
        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>()));
        }
Example #13
0
        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>()));
        }
Example #14
0
        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>()));
        }
Example #15
0
        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>()));
        }
Example #16
0
        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>()));
        }
Example #17
0
        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
            });
        }
Example #19
0
        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>()));
        }
Example #20
0
        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();
            }
        }
Example #21
0
        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>()));
        }
Example #22
0
        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>()));
        }
Example #23
0
        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);
        }
Example #24
0
        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()
            };
        }
Example #25
0
        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());
        }
Example #26
0
        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();
            }
        }
Example #27
0
        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>()));
        }
Example #28
0
        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));
        }
Example #29
0
        public async Task <ActionResult <SheriffDto> > GetSheriffsForTeams()
        {
            var sheriffs = await SheriffService.GetFilteredSheriffsForTeams();

            return(Ok(sheriffs.Adapt <List <SheriffDto> >()));
        }
Example #30
0
 public async Task <IActionResult> GetPhoto(Guid id) => File(await SheriffService.GetPhoto(id), "image/jpeg");